使用不同类型的多个层次结构数据模板更改IsSelected上树视图中的HeaderTemplate
本文关键字:IsSelected 视图 HeaderTemplate 同类型 数据 层次结构 | 更新日期: 2023-09-27 18:25:37
我有一个TreeView
,我想向它添加两种不同的节点类型,每个类型都有自己的HierachicalDataTemplate
。我有这个工作(代码如下)
我想要的是,当树中的任何节点被选中时,我希望该节点的模板发生变化,为BoolNode节点使用不同的模板,为CompareNodes使用不同的模版。我发现了一些使用Styles和Trigger
的示例,但它们都适用于TreeView
,其中所有节点共享相同的模板。
TreeView Xaml:
<TreeView Name="m_kTest">
<TreeView.Resources>
<HierarchicalDataTemplate DataType="{x:Type self:BoolNode}" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding OpText}"/>
</StackPanel>
</HierarchicalDataTemplate>
<HierarchicalDataTemplate DataType="{x:Type self:CompareNode}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Header}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding OpText}"/>
<TextBlock Text=" "/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</HierarchicalDataTemplate>
</TreeView.Resources>
</TreeView>
IQueryNode:
public interface IQueryNode
{
ObservableCollection<IQueryNode> Children { get; }
int OpIndex { get; set; }
String OpText{get;}
}
BoolNode:
public class BoolNode :IQueryNode
{
public int OpIndex { get; set; }
public String OpText { get { ... } }
public ObservableCollection<IQueryNode> Children { get; private set; }
public BoolNode()
{
Children = new ObservableCollection<IQueryNode>();
}
}
CompareNode:
public class CompareNode: IQueryNode
{
public ObservableCollection<IQueryNode> Children { get; private set; }
public int OpIndex { get; set; }
public String OpText {get {...} }
public String Header { get; set; }
public String Value { get; set; }
public CompareNode()
{
Children = new ObservableCollection<IQueryNode>();
}
}
我以一种"黑客"的方式完成了这项工作。
我在两个类中添加了一个"IsSelected"属性,并将其绑定到TreeViewNode的IsSelected属性。然后,由于我只使用了两种数据类型,我添加了一个"IsBoolean"布尔字段,并触发了对这两个值的模板更改:
TreeView Xaml:
<TreeView Name="m_kTest">
<TreeView.Resources>
<HierarchicalDataTemplate x:Key="BoolDisplayTemplate" DataType="{x:Type self:BoolNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="BoolEditTemplate" DataType="{x:Type self:BoolNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="CompareEditTemplate" DataType="{x:Type self:CompareNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<HierarchicalDataTemplate x:Key="CompareDisplayTemplate" DataType="{x:Type self:CompareNode}" ItemsSource="{Binding Children}"> /*template*/ </HierarchicalDataTemplate>
<Style TargetType="{x:Type TreeViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="True"/>
<Condition Binding="{Binding Path=IsSelected}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource BoolDisplayTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="True"/>
<Condition Binding="{Binding Path=IsSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource BoolEditTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="False"/>
<Condition Binding="{Binding Path=IsSelected}" Value="False"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource CompareDisplayTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=IsBoolNode}" Value="False"/>
<Condition Binding="{Binding Path=IsSelected}" Value="True"/>
</MultiDataTrigger.Conditions>
<MultiDataTrigger.Setters>
<Setter Value="{StaticResource CompareEditTemplate}" Property="HeaderTemplate"/>
</MultiDataTrigger.Setters>
</MultiDataTrigger>
</Style.Triggers>
</Style>
</TreeView.Resources>
</TreeView>
IQueryNode:
public interface IQueryNode
{
ObservableCollection<IQueryNode> Children { get; }
int OpIndex { get; set; }
String OpText{get;}
bool IsBoolNode { get; }
bool IsSelected { get; set; }
}
BoolNode:
public class BoolNode :IQueryNode
{
public int OpIndex { get; set; }
public String OpText { get { ... } }
public ObservableCollection<IQueryNode> Children { get; private set; }
public bool IsBoolNode{get{return true;}}
public bool IsSelected { get; set;}
public BoolNode()
{
OpIndex = 0;
Children = new ObservableCollection<IQueryNode>();
IsSelected = false;
}
}
CompareNode:
public class CompareNode: IQueryNode
{
public ObservableCollection<IQueryNode> Children { get; private set; }
public int OpIndex { get; set; }
public String OpText{ get{ ... } }
public String Header { get; set; }
public String Value { get; set; }
public bool IsBoolNode { get { return false; } }
public bool IsSelected { get; set; }
public CompareNode()
{
Children = new ObservableCollection<IQueryNode>();
IsSelected = false;
}
}
以下是我只在选定项目上获得自定义样式的方法
XML:
<Window x:Name="window"
x:Class="stackoverflowTreeview.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:t="clr-namespace:System;assembly=mscorlib"
xmlns:this="clr-namespace:stackoverflowTreeview"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<this:testConv x:Key="testConv"/>
<Style TargetType="TreeView">
<Setter Property="ItemTemplate">
<Setter.Value>
<HierarchicalDataTemplate ItemsSource="{Binding Children}">
<ContentControl>
<ContentControl.Style>
<Style>
<Setter Property="ContentControl.Content">
<Setter.Value>
<!-- This is the default, common template -->
<TextBlock Text="{Binding Name, Converter={StaticResource testConv}}"/>
</Setter.Value>
</Setter>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=TreeViewItem}}" Value="True">
<Setter Property="ContentControl.Content">
<Setter.Value>
<ContentControl Content="{Binding}">
<ContentControl.Resources>
<!-- These templates are type specific, change them for your desired types -->
<DataTemplate DataType="{x:Type this:Herp}">
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
<DataTemplate DataType="{x:Type this:Derp}">
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<TextBlock Text="{Binding Value}"/>
</StackPanel>
</DataTemplate>
</ContentControl.Resources>
</ContentControl>
</Setter.Value>
</Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</HierarchicalDataTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Grid>
<TreeView Name="m_kTest" ItemsSource="{Binding Data, ElementName=window}">
</TreeView>
</Grid>
</Window>
C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;
namespace stackoverflowTreeview
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Data = new List<IHerp>()
{
new Derp("Derp Root", "Derp Root Value")
{
Children = new List<IHerp>()
{
new Herp("Herp Child")
{
Children = new List<IHerp>() {new Derp("Derp Grandchild","Derp GrandChild Value")}
},
new Derp("Derp Child2", "Derp Child2 Value")
{
Children = new List<IHerp>() {new Derp("Derp Grandchild","Derp GrandChild Value")}
},
new Herp("Herp Child")
{
Children = new List<IHerp>() {new Derp("Derp Grandchild","Derp GrandChild Value")}
}
}
}
};
}
public static DependencyProperty dData = DependencyProperty.Register("Data", typeof(List<IHerp>), typeof(MainWindow));
public List<IHerp> Data
{
get { return (List<IHerp>)GetValue(dData); }
set { SetValue(dData, value); }
}
}
public abstract class IHerp : DependencyObject
{
public static DependencyProperty dChildren = DependencyProperty.Register("Children", typeof(List<IHerp>), typeof(IHerp));
public List<IHerp> Children { get { return (List<IHerp>)GetValue(dChildren); } set { SetValue(dChildren, value); } }
public static DependencyProperty dName = DependencyProperty.Register("Name", typeof(string), typeof(IHerp));
public string Name { get{return (string)GetValue(dName);} set{SetValue(dName,value);} }
public IHerp()
{
Children = Children == null ? new List<IHerp>() : Children;
Name = Name == null ? "" : Name;
}
}
public class Herp : IHerp
{
public Herp(string name)
{
Name = name;
}
}
public class Derp : IHerp
{
public string Value { get; set; }
public Derp(string name, string value)
{
Name = name;
Value = value;
}
}
public class testConv : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
try
{
return value;
}
catch { return typeof(object); }
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}