Reputation: 1608
How can I change the bound value depending on the type of the bound item.
I'm using the TreeListView from Christian Ricciolo although it works just the same with the standard TreeView.
I have two classes
class Group
{
public String Name {get;}
public Int32 MaxItems {get;}
public ObservableList<Item> Items {get;}
}
class Item
{
public String Name {get;}
public String Status {get;}
}
The XAML
<Grid>
<r:TreeListView ItemsSource="{Binding}">
<r:TreeListView.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:Group}" ItemsSource="{Binding Items}" />
<DataTemplate DataType="{x:Type local:Item}" />
</r:TreeListView.Resources>
<r:TreeListView.Columns>
<GridViewColumn Header="Name" DisplayMemberBinding="{Binding Path=Name}" />
<GridViewColumn Header="Status" DisplayMemberBinding="???" />
</r:TreeListView.Columns>
</r:TreeListView>
</Grid>
That works fine and I can see all groups and their items.
In the status column I want to display Item.Status
and Group.Items.Count +"/"+ MaxItems
depending on what is actually displayed in that row.
Currently I'm using {Binding Converter={StaticResource testConverter}}
where testConverter generates the output depending on the type, but thats cumbersome and I hope there is a cleaner way.
I cannot/don't want to create a Group.Status
property.
I think I cannot use a in the data templates either, since DisplayMemberBinding overwrites them and I want to be able to do that with multiple columns/bindings.
Upvotes: 0
Views: 268
Reputation: 19020
The only other way I came across so far is to use the CellTemplateSelector
property of the GridViewColumn
. You will need to implement a DataTemplateSelector
to select the proper DataTemplate
. It's a little bit cleaner in the sense that you still define the display layout/content in the xaml and just choose the appropriate template.
Edit: Yes, you can't use DisplayMemberBinding
in this case, however DisplayMemberBinding
is a simple shortcut for a TextBlock
data template bound to the path. However when you use the datatemplate you can do all the binding you need in there - you don't need the DisplayMemberBinding
in this case.
Quick example:
<Grid>
<Grid.Resources>
<r:NameCellTemplateSelector x:Key="NameTemplateSelector"/>
<r:StatusCellTemplateSelector x:Key="StatusTemplateSelector"/>
<Grid.Resources>
...
<GridViewColumn Header="Name" CellTemplateSelector={StaticResource NameTemplateSelector} />
<GridViewColumn Header="Status" CellTemplateSelector={StaticResource StatusTemplateSelector} />
</Grid>
And and implement the selectors:
public class NameCellTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
// find the data template with a specific x:Key
return element.FindResource("someNameTemplate") as DataTemplate;
}
}
public class StatusCellTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
FrameworkElement element = container as FrameworkElement;
// find the data template with a specific x:Key
return element.FindResource("someStatusCellTemplate") as DataTemplate;
}
}
You could probably also get away with just writing one selector as the container
parameter is the UI element and you can walk up the visual tree to find out which column the selector is being called for and choose appropriately based on that. See also the answers to this question: Pass Data to Data Template Selector
Upvotes: 2