ListView inside another ListView does not work - wpf

I am stuck with a strange problem. I have a ListView inside another ListView:
<ListView ItemsSource="{Binding Graph}">
<ListView.Resources>
<DataTemplate DataType="{x:Type model:Node}">
<ListView ItemsSource="{Binding Path=LSC.Elements}">
<DataTemplate DataType="{x:Type model:Entity}">
<TextBlock Text={Binding Name} />
</DataTemplate>
</ListView>
<DataTemplate>
<DataTemplate DataType="{x:Type model:Edge}">
...
</DataTemplate>
</ListView>
</ListView>
All I get is the following exception:
Add value to collection of type 'System.Windows.Controls.ItemCollection' threw an exception
Can you please explain to me what is wrong with my code?

If you would check inner exception it would tell you that
Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.
You forgot about ListView.ItemTemplate or ListView.Resources (depending on how you want to do this) tag in the inner ListView. It should be:
<ListView ItemsSource="{Binding Path=LSC.Elements}">
<ListView.ItemTemplate>
<DataTemplate DataType="{x:Type model:Entity}">
<TextBlock Text={Binding Name} />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
without that it assumes that your DataTemplate is an item and since you already specify ItemSource binding you get this error

Related

How to Use a TreeView as a Binding Source for Other Controls

Consider a Tasks class:
TaskID
ParentID
Title
<several other properties>
Description
SubTasks <-- a collection of tasks
First I populate a hierarchy of Tasks called AllTasks and then load it into the TreeView by:
TaskTree.DataContext = AllTasks
That works fine. Now I want to populate several other controls with the Task data when the user clicks on a Task from the TreeView. I'll just consider the Description property as that is sufficient to illustrate the problem.
My TreeView is defined as follows:
<TreeView
x:Name="TaskTree"
SelectedValuePath="Task">
<TreeView ItemsSource="{Binding}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Path=SubTasks}">
<TextBlock Text="{Binding Path=Title}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</TreeView>
The TextBox that should display the Description property of the Task selected by the user is defined by:
<DockPanel
DataContext="{Binding ElementName=TaskTree}">
<TextBox
x:Name="txtDescription"
Text="{Binding Path=SelectedItem.Discussion}"
</DockPanel>
Nothing is showing up in the TextBox. I tried setting....
Text="{Binding Path=Discussion}"
... but that doesn't work either. I've tried other combinations but to no avail. What works?
You don't select any Task in the outer TreeView named "TaskTree". Remove the outer one:
<TreeView ItemsSource="{Binding}" x:Name="TaskTree">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Task}" ItemsSource="{Binding Path=SubTasks}">
<TextBlock Text="{Binding Path=Title}" />
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
...and then try to bind to its SelectedItem property:
<TextBox x:Name="txtDescription" Text="{Binding Path=SelectedItem.Discussion, ElementName=TaskTree}" />

MahApps.Metro: WindowCommands ItemsSource binding

I am trying to bind a collection of items to the windowcommands of metrowindow. Below is the xaml snippet.
<metro:MetroWindow.WindowCommands>
<metro:WindowCommands ItemsSource="{Binding WindowCommands}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Content="{Binding DisplayName}"
Command="{Binding Callback}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</metro:WindowCommands>
</metro:MetroWindow.WindowCommands>
But it does not display the DisplayName property, but the type name of the bounded datatype. How can I achive the intended behaviour?
Works if you add the template as a resource to the MetroWindow. For this to work you will need to create a WindowCommandViewModel that has Label and Callback properties.
<metro:MetroWindow.Resources>
<DataTemplate DataType="{x:Type viewModels:WindowCommandViewModel}">
<Button Content="{Binding DisplayName}"
Command="{Binding Callback}"/>
</DataTemplate>
</metro:MetroWindow.Resources>

Nested Datagrid in ListBox

I have a datagrid nested inside the ItemTemplate of a ListBox. I'm trying to display a tree like data structure using this. My classes are as follows.
The object in my data context contains a List<Section> named Sections, my ListBox is bound to this. Each Section contains a List<Item> named Items, the DataGrid in eac ItemTemplate is bound to this.
When I run the app, I get a null reference exception from the XAML at the line with the binding. Is there a better/alternative way of doing this, or am I missing a trick with the binding?
<Window.Resources>
<CollectionViewSource x:Key="SectionSource" /><!-- this is initialized and filled with an ObservableCollection<Section> Sections when the window loads-->
</Window.Resources>
<ListBox x:Name="lstIngredients" ItemsSource="{Binding Source={StaticResource SectionSource}}">
<ListBox.ItemTemplate>
<DataTemplate>
<DataTemplate.Resources>
<CollectionViewSource x:Key="itemsSource" Source="{Binding Items}"/>
</DataTemplate.Resources>
<DataGrid x:Name="dgItems" IsReadOnly="false" AutoGenerateColumns="False" SelectionMode="Single" SelectionUnit="FullRow" IsSynchronizedWithCurrentItem="True"
DataContext="{Binding}"
ItemsSource="{Binding Source={StaticResource Items}}"
EnableRowVirtualization="false"
VirtualizingStackPanel.VirtualizationMode="Standard"
<DataGrid.Columns>
<DataGridTemplateColumn Width="2*" Header="{lex:LocText ChickenPing.Shared:Strings:Measurement}">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock x:Name="quantity" Text="{Binding Measurement}" TextTrimming="CharacterEllipsis" TextAlignment="Left"/>
<!-- Null reference on this line caused by the binding. If I set this to any DependencyProperty on an Item object, I get a null reference-->
</DataTemplate>
This need to be path
ItemsSource="{Binding Source={StaticResource Items}}"
ItemsSource="{Binding Path=PropertyThatIsCollection}"
And delete the DataContext line
I eventually tracked this down to an event which was set in one of the TemplateColumns. Switching the event from
<TextBlock x:Name="quantity" Text="{Binding Measurement}" GotFocus="txt_GotFocus" />
to
<Style x:Key="FocusableTextbox" TargetType="{x:Type TextBox}">
<EventSetter Event="GotFocus" Handler="txt_GotFocus" />
</Style>
...
<TextBlock x:Name="quantity" Text="{Binding Measurement}" Style={StaticResource FocusableTextbox} />

WPF : How to create separate Resources for each item in a bound ItemsControl

I want to achieve the following:
My ViewModel exposes a property named 'Categories' which is a collection of CategoryViewModel objects
Each CategoryViewModel object exposes a property called 'Items' which is a collection of strings*.
On my View, I want a TabControl with a TabItem for each object in the 'Categories' collection.
The Content of each TabItem should be a xceed DataGrid control displaying the contents of the selected tab's Items collection.
<TabControl ItemsSource="{Binding Categories}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding CategoryName}" />
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding Items}"
AutoCreateColumns="True">
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
This works ok when I bind directly to the ItemsSource property of the DataGridControl. However, in order to utilize all of the functionality of the DataGridControl, I need to bind the ItemsSource property of the DataGridControl to a DataGridCollectionViewSource object that is bound to my Items collection. I do this when the grid ISN'T nested in another control by creating a DataGridCollectionViewSource object in the Resources section of the UserControl and binding to that.
<UserControl>
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</UserControl.Resources>
<Grid>
<xcdg:DataGridControl
ItemsSource="{Binding Source={StaticResource GridData}}"
AutoCreateColumns="True">
</xcdg:DataGridControl>
</Grid>
</UserControl>
How do I need to structure the XAML so that when the TabControl is being bound, a DataGridCollectionViewSource object is created for each TabItem so that the DataGridControl that is generated within the content of the TabItem can be bound to it?
Clear as mud, right? :)
Thanks!
Notes:
*In the real solution the collection contains objects of a class that is more complex than a simple string, but a string was used to make the example more simple.
OK, this is a bit of a long-shot, but could you use the DataGrid.Tag ...
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding RelativeSource={RelativeSource Self}, Path=Tag}"
AutoCreateColumns="True">
<xcdg:DataGridControl.Tag>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</xcdg:DataGridControl.Tag>
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
Or ... resources can be defined on any FrameworkElement, so you could try:
<TabControl.ContentTemplate>
<DataTemplate>
<xcdg:DataGridControl
ItemsSource="{Binding Source={StaticResource GridData}}"
AutoCreateColumns="True">
<xcdg:DataGridControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
Source="{Binding Items}" />
</xcdg:DataGridControl.Resources>
</xcdg:DataGridControl>
</DataTemplate>
</TabControl.ContentTemplate>
I don't use the eXceed Grid so cannot test whether these work - just a couple of ideas to try!
Colin E.
You can use x:Shared="True" attribute on a resource. That means a new instance is created for every use of that resource.
Example:
<UserControl.Resources>
<xcdg:DataGridCollectionViewSource x:Key="GridData"
x:Shared="False"
Source="{Binding Items}" />
</UserControl.Resources>

How to find a ListView in a DataTemplate?

I have this ListView in xaml
<ListView x:Name="PersonsListView" ItemsSource="{Binding}" ItemTemplate="{DynamicResource personLayout}">
<ListView.Resources>
<DataTemplate x:Key="personLayout" DataType="Person">
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding Path=FullName}"/>
<ListView x:Name="AddressesListView" ItemsSource="{Binding Path=Addresses}"/>
</StackPanel>
</DataTemplate>
</ListView.Resources>
</ListView>
How can I use AddressesListView in code behind?
For instance if I want to do AddressesListView.SelecItem.
Chk out this blog post for more scenarios like this.....
http://blogs.msdn.com/wpfsdk/archive/2007/03/16/how-do-i-programmatically-interact-with-template-generated-elements-part-i.aspx
http://blogs.msdn.com/wpfsdk/archive/2007/04/16/how-do-i-programmatically-interact-with-template-generated-elements-part-ii.aspx
Given an item in the PersonsListView that is of Type Person, you can use the ItemContainerGenerator property on the PersonsListView, and find the container for the data item. You should then bable to use FrameworkElement.FindName(), to find that specific element.
The nested listview looks kinda weird BTW :)

Resources