How to find a ListView in a DataTemplate? - wpf

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 :)

Related

Binding to two dependency properties of the user control which is a ListViewItem

I've created an user control which is a ListViewItem. That control has 2 dependency properties I would like to bind to from my ViewModel. But how am I supposed to do that when I can only bind one thing (collection) to ListView ItemsSource property? How can I bind to ExpanderInfo dependency property? Is there any way to do that or maybe I have made a bad assumption and should have created user control in other way?
Here is my xaml code:
<ListView ItemsSource="{Binding Tasks}" SelectedItem="{Binding SelectedTask}" Height="200" ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding ExpanderStatus}"/>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
Thank you for your help!
Replace <tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding ExpanderStatus}"/> with
<tc:TaskTile TaskInfo="{Binding}" ExpanderInfo="{Binding DataContext.ExpanderStatus, RelativeSource={RelativeSource AncestorType=ListView, Mode=FindAncestor}}"/>

ListView inside another ListView does not work

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

How to override the ItemsSource defined for an ItemTemplate?

I use an Item Template to define how the rows of my grid must be displayed. The grid definition (simplified) shows that the item template source is GridRows (a collection of rows) :
<grid ...>
(...)
<ScrollViewer
ItemTemplate="{StaticResource GridRowItemDataTemplate}"
ItemsSource="{Binding GridRows}" />
</ScrollViewer>
</grid>
So far, so good.
In the item template, the textbox is bound to ImportZoneName, which resolved of course to GridRows[i].ImportZoneName, and this is exactly what I want :
<DataTemplate x:Key="GridRowItemDataTemplate">
<Grid>
<TextBlock {Binding ImportZoneName}" />
<ComboBox
SelectedItem="{Binding SelectedModelingTypeValue}"
ItemsSource="{Binding ModelingTypes}" />
</Grid>
</DataTemplate>
Now the problem : I also want to bind the combo box to an other property (ModelingTypes) of my view model. This property is not linked in any way to GridRows. How can I tell WPF to override (or forget) the item template source?
Many, many thanks !
BTW, I did not find yet a simple guide for these simple binding cases... If anyone have a link to such a guide, I will bless him/her forever :)
You can get the DataContext of the parent list like this:
<DataTemplate x:Key="GridRowItemDataTemplate">
<Grid>
<TextBlock {Binding ImportZoneName}" />
<ComboBox
SelectedItem="{Binding SelectedModelingTypeValue}"
ItemsSource="{Binding DataContext.ModelingTypes,
RelativeSource={RelativeSource FindAncestor,
AncestorType=Grid}}" />
</Grid>
</DataTemplate>
Replace Grid with the type of the grid you are using (not sure which it is, not evident from the question), as long as its DataContext has the property ModelingTypes

WPF Multiple master/details, same grid

I have a TreeView which has three levels.
Lets say its a league, division and team TreeView.
Now, when I select each of the items in the tree, I would like to see detailed information about it.
Whats the best way to achieve this?
Since Grid doesn't items (like a ListBox), I can't just set its ItemsSource and make a DataTemplate...
I thought about using a ListBox which will contain only the selected item but this seems to be very bad...
Thanks.
You first define the 3 DataTemplates for your league, division and team classes. After, you bind the TreeView to the root of your objects. Your League and Division classes should have a Children property that returns the children. All your classes should have a Name property.
Then when you want to show a single object, use the ContentPresenter, and the bind its content to the SelectedItem if the TreeView.
For example:
<StackPanel>
<StackPanel.Resources>
<DataTemplate DataType="{x:Type your_namespace:League}">
<StackPanel Orientation="Vertical">
<TextBlock Text={Binding Name}/>
<.../>
<StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type your_namespace:Division}">
<StackPanel Orientation="Vertical">
<TextBlock Text={Binding Name}/>
<.../>
<StackPanel>
</DataTemplate>
<DataTemplate DataType="{x:Type your_namespace:Team}">
<StackPanel Orientation="Vertical">
<TextBlock Text={Binding Name}/>
<.../>
<StackPanel>
</DataTemplate>
</StackPanel.Resources>
<TreeView x:Name="_tree" ItemsSource="{Binding RootOfYourItems}">
<TreeView.ItemTemplate>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<TextBlock Text={Binding Name}/>
</HierarchicalDataTemplate>
</TreeView>
<ContentPresenter Content="{Binding Path=SelectedItem, ElementName=_tree}" />
</StackPanel>
This code was not tested or compiled, it just provided as an example.
I would create a viewmodel with properties for the tree structur, the current selection and the details to the current selection.
The tree struct is one-way bound to the treeview, the SelectedItem from the treeview is OneWayToSource bound to the current selection property (due to the limitations of the property). This property changes the list of child items once the current selection changes, and the child items are bound to the listbox displaying them.

How can I achieve a binding path which is bound by another binding?

I'm writing my own UserControl which displays data in a ListBox. I want to achieve something similar to a property like "DisplayMemberPath". In my example, it's "EditableMemberPath", which should determine which member will be displayed in the textbox. However, using a binding on a binding does not work.
<ListBox ItemsSource="{Binding Path=Items, ElementName=me}"
SelectedItem="{Binding Path=SelectedItem, ElementName=me}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<Image Source="{Binding Converter={Binding Path=ItemToImageConverter, ElementName=me}}" />
<TextBlock Text="{Binding Path={Binding Path=EditableMemberPath, ElementName=me}}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Can you help me finding a proper solution?
Best Regards
Oliver Hanappi
You can't do that directly in XAML (at least not with the built-in classes) : a Binding is not a DependencyObject, so you can't bind its properties.
However the post mentioned by Martin Harris looks promising...

Resources