这是问题所在。我正在使用几种不同类型的对象绑定TreeView。每个对象都是一个节点,而某些对象有一个名为IsNodeExpanded的属性,当然,其他一些对象则没有。这是我的风格:
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsNodeExpanded, Mode=TwoWay}" />
</Style>
现在,问题是当绑定没有此属性的项时,我们在输出中出现此错误:
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')
当然,我们得到了很多次。所以我试图想出一种基于它所拥有的DataType来切换TreeViewItem样式的方法。关于如何做到这一点的任何想法?
一些信息:我无法手动为每个项目执行此操作,因为我没有在XAML中创建它们,它们是从数据源动态创建的。
编辑:我找到this answer,但它对我不起作用。答案 0 :(得分:8)
尝试将TreeView.ItemContainerStyleSelector
属性与自定义StyleSelector
类一起使用,该类根据绑定对象是否具有该属性来更改样式。
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;
}
}
在XAML资源中:
<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}" />
在XAML中:
<TreeView ItemsSource="{Binding ...}"
ItemContainerStyleSelector="{StaticResource TreeItemStyleSelector}">
答案 1 :(得分:1)
<强>更新强>
<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>
替代方式
除了切换样式之外,您应该使用HierarchicalDataTemplate和DataTemplate来设置TreeViewItem的样式,除非您想要更改某些继承的框架属性,否则它们的工作方式类似。
您可以根据TreeView项目模板绑定的不同类型的对象定义不同的“DataTemplate”和“HeirarchicalDataTemplate”。
这就是为什么这些模板被设计为完全分离你的UI逻辑和代码,使用Selector等或任何这样的编码,你将更多地介绍你的代码背后的UI依赖,WPF不适合。
这是链接, TreeView DataBinding
了解如何在资源中定义项目模板
<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>
答案 2 :(得分:0)
在绑定工作上使用FallbackValue会对你有用吗?如果绑定失败,这将适用...
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding IsNodeExpanded, Mode=TwoWay, FallbackValue=False}" />
</Style>
答案 3 :(得分:0)
基于DataTrigger的解决方案:
<UserControl.Resources>
<converters:DataTypeConverter x:Key="DataTypeConverter"/>
</UserControl.Resources>
<!-- .... -->
<Style TargetType="{x:Type TreeViewItem}">
<Style.Triggers>
<DataTrigger Binding="{Binding Converter={StaticResource DataTypeConverter}}"
Value="{x:Type yourClasses:ClassWithIsNodeExpanded}">
<Setter Property="IsExpanded" Value="{Binding IsNodeExpanded}" />
</DataTrigger>
</Style>
和DataTypeConverter:
namespace Converters
{
/// <summary>
/// Implement an IValueConverter named DataTypeConverter, which accepts an object and returns its Type(as a
/// System.Type):
/// Usage:
/// Change your DataTrigger to use the Converter, and set the value to the Type:
/// <DataTrigger Binding="{Binding SelectedItem,
/// Converter={StaticResource DataTypeConverter}}"
/// Value="{x:Type local:MyType}">
/// ...
/// </DataTrigger>
/// Declare DataTypeConverter in the resources:
/// <UserControl.Resources>
/// <v:DataTypeConverter x:Key="DataTypeConverter"></v:DataTypeConverter>
/// </UserControl.Resources>
/// </summary>
[ValueConversion(typeof(object), typeof(Type))]
public class DataTypeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter,
CultureInfo culture)
{
return value.GetType();
}
public object ConvertBack(object value, Type targetType, object parameter,
CultureInfo culture)
{
throw new NotImplementedException();
}
}
}