Here's the problem. I'm binding a TreeView with a few different types of objects. Each object is a node, and SOME objects have a property called IsNodeExpanded, and of course, some others don't. Here's my style:
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsNodeExpanded, Mode=TwoWay}" />
</Style>
Now, the problem is when binding the items that DON'T have this property, we get this error in the output:
System.Windows.Data Error: 39 : BindingExpression path error: 'IsNodeExpanded' property not found on 'object' ''CompensationChannel' (HashCode=56992474)'. BindingExpression:Path=IsNodeExpanded; DataItem='CompensationChannel' (HashCode=56992474); target element is 'TreeViewItem' (Name=''); target property is 'IsExpanded' (type 'Boolean')
Of course we get it a ton of times. So I'm trying to come up with a way to switch the style of the TreeViewItem based on the DataType it holds. Any idea on how to do this?
Some info: I can't do it manually for each item because I'm not creating them in XAML, they are created dynamically from a data source.
EDIT: I found this answer but it didn't work for me.
Try using the TreeView.ItemContainerStyleSelector
property with a custom StyleSelector
class which changes the style depending if the bound object has that property or not.
public class TreeItemStyleSelector : StyleSelector
{
public Style HasExpandedItemStyle { get; set; }
public Style NoExpandedItemStyle { get; set; }
public override Style SelectStyle(object item, DependencyObject container)
{
// Choose your test
bool hasExpandedProperty = item.GetType().GetProperty("IsExpanded") != null;
return hasExpandedProperty
? HasExpandedItemStyle
: NoExpandedItemStyle;
}
}
In the XAML Resources:
<Style x:Key="IsExpandedStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsNodeExpanded, Mode=TwoWay}" />
</Style>
<Style x:Key="NoExpandedStyle" TargetType="{x:Type TreeViewItem}">
</Style>
<x:TreeViewItemStyleSelector x:Key="TreeViewItemStyleSelector"
HasExpandedItemStyle="{StaticResource IsExpandedStyle}"
NoExpandedItemStyle="{StaticResource NoExpandedStyle}" />
In the XAML:
<TreeView ItemsSource="{Binding ...}"
ItemContainerStyleSelector="{StaticResource TreeItemStyleSelector}">
UPDATE
<TreeView.Resources>
... following is only for one type of data
<HierarchicalDataTemplate
DataType="{x:Type local:RegionViewModel}"
ItemsSource="{Binding Children}"
>
... define your style
<HierarchicalDataTemplate.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}"
... following line is necessary
BasedOn="{StaticResource {x:Type TreeViewItem}}">
..... your binding stuff....
</Style>
</HierarchicalDataTemplate.ItemContainerStyle>
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16"
Margin="3,0" Source="Images\Region.png" />
<TextBlock Text="{Binding RegionName}" />
</StackPanel>
</HierarchicalDataTemplate>
...
</TreeView.Resources>
ALTERNATIVE WAY
Instead of Switching Styles, you should use HierarchicalDataTemplate and DataTemplate in order to style your TreeViewItem, they will work similarly unless you want to change certain inherited framework properties.
You can define different "DataTemplate" and "HeirarchicalDataTemplate" based on different types of object that are bound to for Item Template of TreeView.
And that is why these templates are designed to completely seperate your UI logic and code behind, using Selector etc or any such coding, you will introduce UI dependency more on your code behind, which WPF is not intended for.
Here is the link, TreeView DataBinding
And see how you can define item templates in resources,
<TreeView.Resources>
<HierarchicalDataTemplate
DataType="{x:Type local:RegionViewModel}"
ItemsSource="{Binding Children}"
>
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16"
Margin="3,0" Source="Images\Region.png" />
<TextBlock Text="{Binding RegionName}" />
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate
DataType="{x:Type local:StateViewModel}"
ItemsSource="{Binding Children}"
>
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16"
Margin="3,0" Source="Images\State.png" />
<TextBlock Text="{Binding StateName}" />
</StackPanel>
</HierarchicalDataTemplate>
<DataTemplate DataType="{x:Type local:CityViewModel}">
<StackPanel Orientation="Horizontal">
<Image Width="16" Height="16"
Margin="3,0" Source="Images\City.png" />
<TextBlock Text="{Binding CityName}" />
</StackPanel>
</DataTemplate>
</TreeView.Resources>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With