I write a program for edition of IIS web.config file. I have a problem with my TreeView control which doesn't want to refresh itself after I change something in the source XmlDocument variable.
It's the WPF project.
Window resources in XAML:
<Window.Resources>
<XmlDataProvider x:Key="XmlData" />
</Window.Resources>
My TreeView:
<TreeView x:Name="XmlTree" Grid.Row="1"
ItemsSource="{Binding Source={StaticResource XmlData}, XPath=*}"
ItemTemplate="{StaticResource NodeTemplate}"
SelectedItemChanged="XmlTree_SelectedItemChanged" />
TreeView style:
<DataTemplate x:Key="AttributeTemplate">
<StackPanel Orientation="Horizontal"
Margin="3,0,0,0"
HorizontalAlignment="Center">
<TextBlock Text="{Binding Path=Name}"
Foreground="{StaticResource xmAttributeBrush}" FontFamily="Consolas" FontSize="8pt" />
<TextBlock Text="=""
Foreground="{StaticResource xmlMarkBrush}" FontFamily="Consolas" FontSize="8pt" />
<TextBlock Text="{Binding Path=Value}"
Foreground="{StaticResource xmlValueBrush}" FontFamily="Consolas" FontSize="8pt" />
<TextBlock Text="""
Foreground="{StaticResource xmlMarkBrush}" FontFamily="Consolas" FontSize="8pt" />
</StackPanel>
</DataTemplate>
<HierarchicalDataTemplate x:Key="NodeTemplate">
<StackPanel Orientation="Horizontal" Focusable="False">
<TextBlock x:Name="tbName" Text="?" FontFamily="Consolas" FontSize="8pt" />
<ItemsControl
ItemTemplate="{StaticResource AttributeTemplate}"
ItemsSource="{Binding Path=Attributes}"
HorizontalAlignment="Center">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
</StackPanel>
<HierarchicalDataTemplate.ItemsSource>
<Binding XPath="*" />
</HierarchicalDataTemplate.ItemsSource>
<HierarchicalDataTemplate.Triggers>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Text">
<Setter TargetName="tbName" Property="Text" Value="{Binding Path=Value}"/>
</DataTrigger>
<DataTrigger Binding="{Binding Path=NodeType}" Value="Element">
<Setter TargetName="tbName" Property="Text" Value="{Binding Path=Name}"/>
</DataTrigger>
</HierarchicalDataTemplate.Triggers>
</HierarchicalDataTemplate>
Code behind:
private XmlDocument _xml;
private XmlElement _selectedElement; // actually selected item in TreeView
private XmlDataProvider _xmlDataProvider;
private string _tempFileName = #"C:\test.xml";
public MainWindow()
{
InitializeComponent();
XmlTree.Style = (Style)FindResource("TreeViewAllExpandedStyle");
_xmlDataProvider = FindResource("XmlData") as XmlDataProvider;
}
private void OpenXmlFile(string filePath)
{
XmlEditor.Clear(); // my text editor provided by AvalonEdit
XmlEditor.Load(filePath);
_xml = new XmlDocument();
_xml.Load(filePath);
if(_xmlDataProvider.Document == null)
_xmlDataProvider.Document = _xml;
}
private void saveChangesButton_Click(object sender, EventArgs e)
{
// some changes on _selectedElement (changes applies also into _xml)
_xml.Save(_tempFileName);
RefreshViews();
}
private void RefreshViews()
{
//
OpenXmlFile(_tempFileName);
// here I want to refresh my TreeView
// I noticed that when I select back my changed item, its values are set, but in my tree I see the old ones...
// I tried to do XmlTree.Focus() (nothing happens excepting control focus)
// and _xmlDataProvider.Refresh() (here comes NullReferenceException)
// I guess something bad happens in OpenXmlFile(...) method, because I reopen _xml and _xmlDataProvider looses a handler to it?
}
Could anyone explain why it doesn't work?
[edit]
I tried to modify 2 methods like this:
private void OpenXmlFile(string filePath)
{
XmlEditor.Clear();
XmlEditor.Load(filePath);
_xml = new XmlDocument();
_xml.Load(filePath);
_xmlDataProvider.Document = _xml;
}
private void saveChangesButton_Click(object sender, EventArgs e)
{
// ...
_xmlDataProvider.Document.Save(_tempFileName);
_xmlDataProvider.Refresh();
}
And now I get NullReferenceException while _xmlDataProvider.Refresh();
Hello you can try with Binding Two-Way on your TreeView and observable collection.
{Binding .... Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
Firslty you can modify your binding
ItemsSource="{Binding Source={StaticResource XmlData}, XPath=*, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
You are only setting the value of xmlDataProvider.Document in your OpenXmlFile() function if it is null. When you set
_xml = new XmlDocument();, it sets _xml to point to a new object, but xmlDataProvider is still pointing to the old object. Then, you have the following two lines:
if(_xmlDataProvider.Document == null)
_xmlDataProvider.Document = _xml;
If you're getting in here from RefreshViews(), _xmlDataProvider.Document will not be null, so you're never refreshing the XML file tied to your data provider.
Related
I have data stored in IGroupping field of my repository class. I want to create tab item for each group of this collection, showing it`s items in listbox.
This is my code for creating tab items:
foreach (var group in repository.Products)
{
var tab = new MyTabItem();
tab.Header = group.Key;
tab.Products = group.AsEnumerable().ToList();
tab.FontSize = 16;
TabControlProducts.Items.Add(tab);
}
TabControlProducts.SelectedIndex = 0;
Here`s part of my xaml file:
<TabControl Grid.Row="1" Grid.Column="1" x:Name="TabControlProducts">
<TabControl.ContentTemplate>
<DataTemplate>
<ListBox FontSize="16" ItemsSource="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type local:MyTabItem}}, Path=Products}" Visibility="Visible">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Code.MainGroup}"></TextBlock>
<TextBlock Text="{Binding Path=Code.MainForm}"></TextBlock>
<TextBlock Text="{Binding Path=Code.SubForm}"></TextBlock>
<TextBlock Text="{Binding Path=Code.Finishing}"></TextBlock>
<TextBlock Text="{Binding Path=Code.MaterialGroup}"></TextBlock>
<TextBlock Text="{Binding Path=Code.MaterialSort}"></TextBlock>
<TextBlock Text="{Binding Path=Code.Attest}"></TextBlock>
<TextBlock Text="{Binding Path=Code.Sizing}"></TextBlock>
<TextBlock Text="{Binding Path=Code.SubSizing}"></TextBlock>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
And declaration of MyTabItem class:
public class MyTabItem : TabItem
{
public List<Product> Products;
}
Now I have listboxes displayed in each of tab items, but they are empty
It's probably easier to bind directly to your product class and let the TabControl wrap each one in a TabItem.
foreach (var group in repository.Products)
{
TabControlProducts.Items.Add(group);
}
TabControlProducts.SelectedIndex = 0;
Then the xaml
<TabControl Grid.Row="1" Grid.Column="1" x:Name="TabControlProducts">
<TabControl.Resources>
<Style TargetType="TabItem">
<Setter Property="Header" Value="{Binding Key}"/>
</Style>
</TabControl.Resources>
<TabControl.ContentTemplate>
<DataTemplate>
<ListBox FontSize="16" ItemsSource="{Binding .}" Visibility="Visible">
itemtemplate here...
</ListBox>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
The latest in my endeavors - I've managed to populate a treeview with elements, and populate a listbox next to it with related elements.
The trick is that, I'm trying to think of a way to assign each listbox item and corresponding treeview item it's own grid row, that would be generated probably in back C# code to with corresponding row definitions based on the control's number of children, if that makes any sense.
I've tried looking at the post below to see if I can select each treeview item this way, but to no avail:
How to programmatically select an item in a WPF TreeView?
Here's some example code that tries to implement this - I keep getting null values, though, and using UpdateLayout() before the loop on the controls doesn't seem to help. :/
for (int i = 0; i < loadedAR.Item2.Count; i++)
{
DABsAndIssuesGrid.RowDefinitions.Add(new RowDefinition());
var selectedItemObjectDAB = DABView.Items.GetItemAt(i);
var DABParent = DABView.Parent;
TreeViewItem currentItemDAB = DABView.ItemContainerGenerator.ContainerFromItem(selectedItemObjectDAB)
as TreeViewItem;
if (currentItemDAB != null)
Grid.SetRow(currentItemDAB, i);
var selectedItemObjectErr = IssueBox.Items.GetItemAt(i);
TreeViewItem currentItemErr = DABView.ItemContainerGenerator.ContainerFromItem(selectedItemObjectErr)
as TreeViewItem;
if (currentItemErr != null)
Grid.SetRow(currentItemErr, i);
}
Is there a better way to do this than the way I'm trying to do it? I've tried using a converter to assign the row dynamically too as they would get generated, but that still appears to put all of my children in the same first grid row...
Here's my XAML:
<Window x:Class="Client_Invoice_Auditor.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Client_Invoice_Auditor"
xmlns:self="clr-namespace:Client_Invoice_Auditor.CoreClient"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="1000">
<Window.Resources>
<self:SelfPayConverter x:Key="FINConverter"/>
<self:ErrorExpandConverter x:Key="ErrorExpandConverter"/>
<self:AssignRowConverter x:Key="AssignRowConverter"/>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="20*"/>
<RowDefinition Height="80*"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.Column="0">
<StackPanel Orientation="Vertical">
<DockPanel VerticalAlignment="Top" Height="20" Panel.ZIndex="1">
<Menu Name="fileMenu" Width="Auto" DockPanel.Dock="Top">
<MenuItem Header="File">
<MenuItem Header="Open Account File" Click="menuOpenFile_Click"/>
<MenuItem Header="Exit" Click="menuExit_Click"/>
</MenuItem>
<MenuItem Header="Options">
<!--<MenuItem Header="Update" Click="update_Click"/>-->
<MenuItem Header="About" Click="about_Click"/>
</MenuItem>
</Menu>
</DockPanel>
<WrapPanel Orientation="Horizontal" HorizontalAlignment="Center" Height="Auto">
<StackPanel Width="Auto" Orientation="Horizontal" HorizontalAlignment="Center">
<Border BorderBrush="MediumAquamarine" BorderThickness="2">
<Label Name="AccountNumber"/>
</Border>
<Border BorderBrush="MediumAquamarine" BorderThickness="2">
<Label Name="AcctDesc"/>
</Border>
<Border BorderBrush="MediumAquamarine" BorderThickness="2">
<Label Name="Organization"/>
</Border>
</StackPanel>
</WrapPanel>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<Label Margin="20,10,0,0" Content="Activity Date Time" />
<Label Margin="60,10,0,0" Content="Beginning Balance" />
<Label Margin="10,10,0,0" Content="Charge Amount" />
<Label Margin="30,10,0,0" Content="Adjustments" />
<Label Margin="40,10,0,0" Content="Payments" />
<Label Margin="60,10,0,0" Content="End Balance" />
<Label Margin="50,10,0,0" Content="Issues" />
</StackPanel>
</StackPanel>
</Grid>
<Grid Grid.Row="1" Grid.Column="0">
<Grid Name="DABsAndIssuesGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*"/>
<ColumnDefinition Width="20*"/>
</Grid.ColumnDefinitions>
<TreeView Name="DABView" Grid.Column="0">
<!--<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded"
Value="{Binding FinClass, Converter={StaticResource ErrorExpandConverter}}" />
</Style>-->
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded"
Value="{Binding Dummies, Converter={StaticResource ErrorExpandConverter}}" />
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type self:dailyAccountBalance}" ItemsSource="{Binding Dummies}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" IsEnabled="False">
<TextBlock Width="150" Text="{Binding DabActivityDate}" />
<TextBlock Width="100" Margin="20,0,0,0" Text="{Binding BegBalance}"/>
<TextBlock Width="100" Margin="20,0,0,0" Text="{Binding ChrgAmount}" />
<TextBlock Width="100" Margin="20,0,0,0" Text="{Binding AdjAmount}" />
<TextBlock Width="100" Margin="20,0,0,0" Text="{Binding PmtAmount}" />
<TextBlock Width="100" Margin="20,0,0,0" Text="{Binding EndBalance}" />
</StackPanel>
<HierarchicalDataTemplate.ItemTemplate>
<DataTemplate DataType="{x:Type self:DummyItem}">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<!--<TextBlock Text="{Binding Text}" />-->
<DataGrid ItemsSource="{Binding ChargeActivities}" AutoGenerateColumns="False">
<DataGrid.Style>
<Style TargetType="{x:Type DataGrid}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=Items.Count,
RelativeSource={RelativeSource Self}}" Value="0">
<Setter Property="Visibility" Value="Collapsed" />
</DataTrigger>
</Style.Triggers>
</Style>
</DataGrid.Style>
<DataGrid.Columns>
<DataGridTextColumn x:Name="ChrgID" Header=" Charge" Binding="{Binding ChargeID}" />
<DataGridTextColumn x:Name="ChrgType" Header="Charge Type" Binding="{Binding ChargeType}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<Trigger Property="Text" Value="CR">
<Setter Property="Foreground" Value="Red"/>
</Trigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn x:Name="ChrgAmt" Header="Amount" Binding="{Binding ChargeAmount}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Style.Triggers>
<DataTrigger Binding="{Binding ChargeType}" Value="CR">
<Setter Property="Foreground" Value="Red"/>
</DataTrigger>
</Style.Triggers>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
<DataGridTextColumn x:Name="FIN" Header="FIN" Binding="{Binding EncntrAlias}" />
<DataGridTextColumn x:Name="FINClass" Header="FIN Class" Binding="{Binding FinClass}">
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="{Binding FinClass, Converter={StaticResource FINConverter}}"/>
</Style>
</DataGridTextColumn.ElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</DataTemplate>
</HierarchicalDataTemplate.ItemTemplate>
</HierarchicalDataTemplate>
<!--<TreeViewItem x:Key="Test">
<TextBlock Text="Me gusta"></TextBlock>
</TreeViewItem>-->
</TreeView.ItemTemplate>
</TreeView>
<Border Grid.Column="1" BorderBrush="Black" BorderThickness="2">
<ListBox Name="IssueBox" ItemsSource="{Binding}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="Hi"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Border>
</Grid>
</Grid>
</Grid>
</Window>
And, here's the code behind:
using Client_Invoice_Auditor.CoreClientAR;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Client_Invoice_Auditor
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public string accountFile;
public MainWindow()
{
InitializeComponent();
OpenaccountFile();
}
private void OpenaccountFile()
{
accountFile = "";
//errorFilters.Clear();
// Displays an OpenFileDialog so the user can select a file.
Microsoft.Win32.OpenFileDialog openFileDialog1 = new Microsoft.Win32.OpenFileDialog();
openFileDialog1.Filter = "Account Files|*.acct";
openFileDialog1.Title = "Select an account File";
if (openFileDialog1.ShowDialog() == true)
{
// Assign the cursor in the Stream to the Form's Cursor property.
accountFile = openFileDialog1.FileName;
//claimFile = openFileDialog1.OpenFile().ToString();
//openFileDialog1.Dispose();
}
if (accountFile == "")
{
/*System.Windows.MessageBox.Show("File must be selected in order to continue - exiting now."
, "No File Selected", MessageBoxButton.OK);
this.Close();*/
if (!AcctDesc.HasContent)
{
AcctDesc.Content = "No Account File Loaded";
//Version version = Assembly.GetExecutingAssembly().GetName().Version;
//manualBreakItem.IsEnabled = false;
//manualValidateItem.IsEnabled = false;
}
}
else
{
//openFileDialog1 = null;
Console.WriteLine("Account file path is: " + accountFile);
//claimFile = "C:\\Users\\KO054202\\Documents\\pft_1450_out\\pft_1450_out\\CAR837I125114220170601.out";
DataTable dataAR = new DataTable();
try
{
Tuple<accountARHeader, List<dailyAccountBalance>, DataTable> loadedAR = dabARLoader.LoadARData(accountFile);
//dataAR = loadedAR.Item2;
AccountNumber.Content = "Account Number: " + loadedAR.Item1.AccountNumber;
AcctDesc.Content = "Description: " + loadedAR.Item1.AccountDescription;
Organization.Content = "Client Organization: " + loadedAR.Item1.OrganizationName;
//TreeViewItem dummy = new TreeViewItem();
//dummy.DataContext = "Hi";
//DummyItem testThis = new DummyItem("Test2");
//testThis.Text = "Hi";
//loadedAR.Item2.First().Dummies.Add(testThis);
DABView.ItemsSource = loadedAR.Item2;
IssueBox.ItemsSource = dabARLoader.loadIssues(loadedAR.Item2);
DABView.UpdateLayout();
for (int i = 0; i < loadedAR.Item2.Count; i++)
{
DABsAndIssuesGrid.RowDefinitions.Add(new RowDefinition());
var selectedItemObjectDAB = DABView.Items.GetItemAt(i);
var DABParent = DABView.Parent;
TreeViewItem currentItemDAB = DABView.ItemContainerGenerator.ContainerFromItem(selectedItemObjectDAB)
as TreeViewItem;
if (currentItemDAB != null)
Grid.SetRow(currentItemDAB, i);
var selectedItemObjectErr = IssueBox.Items.GetItemAt(i);
TreeViewItem currentItemErr = DABView.ItemContainerGenerator.ContainerFromItem(selectedItemObjectErr)
as TreeViewItem;
if (currentItemErr != null)
Grid.SetRow(currentItemErr, i);
}
//DABView.DisplayMemberPath = "A";
}
catch (Exception e)
{
System.Windows.MessageBox.Show("I don't wanna open this file! Try another. Error: " + e.Message);
OpenaccountFile();
}
}
}
private void menuOpenFile_Click(object sender, RoutedEventArgs e)
{
OpenaccountFile();
}
private void menuExit_Click(object sender, RoutedEventArgs e)
{
Close();
}
private void about_Click(object sender, RoutedEventArgs e)
{
System.Windows.MessageBox.Show("I heard you like clicking buttons.");
}
}
}
I have a TreeView inside of a Grid, along with a ListBox control. The
idea is that the TreeView would populate parent items by a daily
account balance, and then for each one of those an adjacent list of
issues would be displayed in the neighboring ListBox
I would make specialized Data Transfer Object (DTO)s where each instance item generates the values for the properties to be shown and where required creates child DTOs for that instance. Then those DTOs are bindable between all the controls. Meaning that you have this class defined
<Top Level Class used by the grid<DTO>>
<Properties et all>
<List of Items in for treeview>
<Treeview class <DTO>>
<Properties et all>
<List of Items in for listbox>
<Listbox class <DTO>>
<Properties et all>
Then bind the grid to the above top level DTO list.
Bind the treeview to the current row's treeview list items.
Bind the listbox to the current treeview's selected item's Listbox items list.
Once the DTOs are created then it simply becomes an exercise in binding.
I grouped my items (products of order) from database by using DataGrid.Group, I grouped it as orders, so it looks like this: Order Number: #{Here I placed real ID from database }, example Order Number: #10, and what I want to do now, is to place button next to that text which is contained in dock panel, and when I click on that button I want to do some action with that orders and because I allready have real order id in header I should "take" it somehow, so I can do in code behind something like : remove order, mark it as proceed or something like that, here is how it looks right now and below is code also:
<DataGrid.Columns >
<DataGridTextColumn Binding="{Binding ProductName}" ElementStyle="{StaticResource LeftAligElementStyle}" Header="Product Name}" MinWidth="350" Foreground="White" FontSize="20" FontFamily="Verdana" />
<DataGridTextColumn Binding="{Binding Quantity}" ElementStyle="{StaticResource LeftAligElementStyle}" Header="Quantity" MinWidth="200" Foreground="White" FontSize="20" FontFamily="Verdana" />
</DataGrid.Columns>
<DataGrid.GroupStyle>
<!-- Style for groups at top level. -->
<GroupStyle>
<GroupStyle.ContainerStyle>
<Style TargetType="{x:Type GroupItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type GroupItem}">
<Expander IsExpanded="True" Background="Black" Opacity="0.7">
<Expander.Header >
<DockPanel Height="50" Margin="0,0,0,0" Name="dockPanel" Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}, Path=ActualWidth}">
<Button Name="btnOrders" Content="Test" Margin="0,0,200,0" DockPanel.Dock="Right" />
<TextBlock FontWeight="Normal" FontFamily="Verdana" FontSize="20" Height="25" Foreground="#83D744" Text="{Binding Path=Name,StringFormat= Order Number:# {0}}" />
</DockPanel>
</Expander.Header>
<Expander.Content>
<ItemsPresenter />
</Expander.Content>
</Expander>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</GroupStyle.ContainerStyle>
</GroupStyle>
</DataGrid.GroupStyle>
Code behind:
public MainWindow()
{
try
{
InitializeComponent();
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
this.WindowState = WindowState.Maximized;
CollectionViewSource collectionViewSource = new CollectionViewSource();
var ordersList = OrdesrController.localOrders();
collectionViewSource.Source = ordersList;
collectionViewSource.GroupDescriptions.Add(new PropertyGroupDescription("NumberOfOrder"));
DataContext = collectionViewSource;
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Handle Click event of your Button.
<Button Name="btnOrders" Click="Button_Click" .../>
private void Button_Click(object sender, RoutedEventArgs e)
{
Button b = sender as Button;
CollectionViewGroup group = b.DataContext as CollectionViewGroup;
/* make clever use of this group */
}
I have a ListView within a DataGridTemplateColumn, if the mouse cursor is over an item within the ListView and the user attempts to scroll the DataGrid, the DataGrid doesn't scroll.
I have tried the following but it still occurs:
<ListView ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" ...
Edit: Providing example below of where this is used, I'm using ListView to make the items wrap on overflow.
<DataGridTemplateColumn Header="Name" Width="120" ScrollViewer.IsDeferredScrollingEnabled="True">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ListView ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" VerticalAlignment="Center" ItemsSource="{Binding DataList}">
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Width="{Binding (FrameworkElement.ActualWidth), RelativeSource={RelativeSource AncestorType=ScrollContentPresenter}}" ItemWidth="{Binding (ListView.View).ItemWidth, RelativeSource={RelativeSource AncestorType=ListView}}" ItemHeight="{Binding (ListView.View).ItemHeight, RelativeSource={RelativeSource AncestorType=ListView}}"/>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock>
<Hyperlink TextDecorations="{x:Null}" NavigateUri="{Binding Path=.}" RequestNavigate="Name_RequestNavigate">
<TextBlock Padding="1" Text="{Binding Path=., Converter={StaticResource NameToLocale}}"/>
</Hyperlink>
</TextBlock>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
Try this ways:
A) Change list view ControlTemplate to remove ScrollViewer from it:
<ListView>
<ListView.Template>
<ControlTemplate>
<ItemsPresenter/>
</ControlTemplate>
</ListView.Template>
...
</ListView>
B) Another way is create a behavior for parent element base on this answer
// Used on sub-controls of an expander to bubble the mouse wheel scroll event up
public sealed class BubbleScrollEvent : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseWheel += AssociatedObject_PreviewMouseWheel;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseWheel -= AssociatedObject_PreviewMouseWheel;
base.OnDetaching();
}
void AssociatedObject_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
e.Handled = true;
var e2 = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta);
e2.RoutedEvent = UIElement.MouseWheelEvent;
AssociatedObject.RaiseEvent(e2);
}
}
<SomePanel>
<i:Interaction.Behaviors>
<viewsCommon:BubbleScrollEvent />
</i:Interaction.Behaviors>
</SomePanel>
I am creating custom phone book which reads phone book contacts and displays inside my application. So I am creating a long list selector and a listbox inside it.
My listbox will contain phone contact name and list of phone number with the check box under the particular name. I wrote an event trigger inside my listbox to make track of the checkbox is clicked or not.
PROBLEM : Event is not firing in the view model. I suspect since the listbox is present inside another list(long list selector), event is not firing.
Here is xaml code:
<phone:LongListSelector Grid.Row="3" LayoutMode="List" ItemsSource="{Binding PhoneBookDataSource}" IsGroupingEnabled="True" HideEmptyGroups="True">
<phone:LongListSelector.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical" >
<TextBlock Text="{Binding PhoneContactName}" FontWeight="SemiBold" FontSize="36" Foreground="Green"></TextBlock>
<ListBox ItemsSource="{Binding LstPhoneContactNumber,Mode=TwoWay}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Tap">
<i:InvokeCommandAction Command="{Binding PhoneNumberCheckedStateChangeCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="480">
<TextBlock Text="{Binding PhoneNumberItem}" FontSize="25" HorizontalAlignment="Left" VerticalAlignment="Center" Foreground="Gray"></TextBlock>
<CheckBox Foreground="Black" Background="Black" VerticalAlignment="Center" HorizontalAlignment="Right" IsChecked="{Binding IsPhoneNumberItemChecked,Mode=TwoWay}"></CheckBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</phone:LongListSelector.ItemTemplate>
<phone:LongListSelector.GroupHeaderTemplate>
<DataTemplate>
<Border Background="Transparent" Padding="5">
<Border Background="{StaticResource PhoneAccentBrush}" BorderBrush="{StaticResource PhoneAccentBrush}" BorderThickness="2" Width="62"
Height="62" Margin="0,0,18,0" HorizontalAlignment="Left">
<TextBlock Text="{Binding Key}" Foreground="{StaticResource PhoneForegroundBrush}" FontSize="48" Padding="6"
FontFamily="{StaticResource PhoneFontFamilySemiLight}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
</Border>
</Border>
</DataTemplate>
</phone:LongListSelector.GroupHeaderTemplate>
<phone:LongListSelector.JumpListStyle>
<Style TargetType="phone:LongListSelector">
<Setter Property="GridCellSize" Value="113,113"/>
<Setter Property="LayoutMode" Value="Grid" />
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<Border Background="{Binding Converter={StaticResource BackgroundConverter}}" Width="113" Height="113" Margin="6" >
<TextBlock Text="{Binding Key}" FontFamily="{StaticResource PhoneFontFamilySemiBold}" FontSize="48" Padding="6"
Foreground="{Binding Converter={StaticResource ForegroundConverter}}" VerticalAlignment="Center"/>
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</phone:LongListSelector.JumpListStyle>
</phone:LongListSelector>
Here is my view model:
public DelegateCommand PhoneNumberCheckedStateChangeCommand { get; set; }
public DelegateCommand SendSMSCommand { get; set; }
public CustomPhoneBookViewModel(INavigationService nav, IDataService data, IAESEnDecrypt encrypt, IGeoLocationService geoLocation, IMessageBus msgBus, ISmartDispatcher smartDispatcher)
: base(nav, data, encrypt, geoLocation, msgBus, smartDispatcher)
{
IsProgressBarBusy = true;
PhoneContactsList = new ObservableCollection<PhoneBookEntity>();
PhoneBookDataSource = new ObservableCollection<LLSAlphaKeyGroup<PhoneBookEntity>>();
InitializeDelegateCommands();
GetDeviceResolution();
ReadPhoneBook();
}
private void OnPhoneNumberItemCheckedStateChangedCommand()
{
try
{
foreach (var parentItem in PhoneBookDataSource)
{
foreach (var childItem in parentItem)
{
foreach (var item in childItem.LstPhoneContactNumber)
{
if (item.IsPhoneNumberItemChecked)
IsSendSMSButtonEnabled = true;
return;
}
}
IsSendSMSButtonEnabled = false;
}
}
catch { }
finally
{
SendSMSCommand.RaiseCanExecuteChanged();
}
}
Any suggestions is appreciated!!
The easiest way of making the nested ListBox interaction bind to the global ViewModel (instead of to its own, nested DataContext) is to assign a unique name to the outmost LongListSelector:
<phone:LongListSelector x:Name="OuterList" Grid.Row="3" LayoutMode="List" ItemsSource="{Binding PhoneBookDataSource}" IsGroupingEnabled="True" HideEmptyGroups="True">
and explicitly bind the Command to this element's DataContext (which is the global ViewModel):
<i:InvokeCommandAction Command="{Binding ElementName=OuterList, Path=DataContext.PhoneNumberCheckedStateChangeCommand}" />