WPF TreeView 检测SelectedItem变化的简单方案
TreeView无法绑定SelectedItem,而又想知道treeview的selecteditem的变化,当然目前有很多方法,我这里简单的提供一个。
目前主要思路就是通过处理xaml的TreeViewItem的IsSelected属性来进行绑定。
<TreeView BorderThickness="0" Width="220" ItemsSource="{Binding Items, IsAsync=True}" HorizontalAlignment="Left"> <TreeView.ItemContainerStyle> <Style TargetType="{x:Type TreeViewItem}"> <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" /> <Setter Property="FontWeight" Value="Normal" /> <Setter Property="HorizontalAlignment" Value="Left" /> <Style.Triggers> <Trigger Property="IsSelected" Value="True"> <Setter Property="FontWeight" Value="Bold" /> </Trigger> </Style.Triggers> </Style> </TreeView.ItemContainerStyle> <TreeView.ItemTemplate> <HierarchicalDataTemplate ItemsSource="{Binding Items, IsAsync=True}"> <Label Content="{Binding Name}" /> </HierarchicalDataTemplate> </TreeView.ItemTemplate> </TreeView>
主要部分是
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
这里的意思就是绑定到集合泛型的IsSelected属性。
这里呢主要是通过抽象类去实现的也就是:
public abstract class TreeViewItemModel<T> : Notify { private bool _IsSelected; public bool IsSelected { get { return _IsSelected; } set { _IsSelected = value; OnChanged(); if (value) { IChanged<T> changed = ModelChangedManger.Sub.Get<T>(); if (changed?.Accepted == true) { changed.OnModelChanged((T)Convert.ChangeType(this, typeof(T))); } } } } }
具体的使用类再去继承即可,也就是
public class GroupModel : TreeViewItemModel<GroupModel> { public GroupModel() { Id = Guid.NewGuid(); } private Guid _id; public Guid Id { get { return _id; } set { _id = value; OnChanged(); } } private string _name; public string Name { get { return _name; } set { _name = value; OnChanged(); } } private ObservableCollection<GroupModel> _Item = new ObservableCollection<GroupModel>(); public ObservableCollection<GroupModel> Items { get { return _Item; } set { _Item = value; OnChanged(); } } }
处理完这样,我们只是完成了一部分。这里这来说下
if (value) { IChanged<T> changed = ModelChangedManger.Sub.Get<T>(); if (changed?.Accepted == true) { changed.OnModelChanged((T)Convert.ChangeType(this, typeof(T))); } }
这个是干什么的。
很明显,Isslected属性触发,我们想通知viewmodel,treeview的selecteditem属性变了,或者叫做selectindex也变了的意思。所以简单的实现了一个事件聚合器,这个部分代码比较简单,整体如下
public interface IChanged<T> { void OnModelChanged(T Model); bool Accepted { get; set; } } public sealed class ModelChangedManger { private ModelChangedManger() { } static ModelChangedManger() { } private class Inner { private Inner() { } internal readonly static ModelChangedManger manger = new ModelChangedManger(); } private ConcurrentDictionary<Type, object> Keys { get; set; } = new ConcurrentDictionary<Type, object>(); public IChanged<T> Get<T>() { if (Keys.TryGetValue(typeof(T), out object val)) { return val as IChanged<T>; } return null; } public void Set<T>(IChanged<T> model) { if (!Keys.ContainsKey(typeof(T))) { Keys.TryAdd(typeof(T), model); } } public void Remove<T>() { Keys.TryRemove(typeof(T), out _); } public static ModelChangedManger Sub { get => Inner.manger; } }
主要是Ichanged接口和manger的一起搭配使用。使用字典将要引发和被引发的类型,类存储起来,这样就可以全局或者大范围的使用了。
同理 我们需要viewmodel上继承一个引发事件的ichanged类
public abstract class TreeViewModel<T> : Notify, IChanged<T> { public virtual void OnModelChanged(T Model) { SelectedItem = Model; } private bool _Accepted; public bool Accepted { get { return _Accepted; } set { _Accepted = value; OnChanged(); } } private T _SelectedItem; public T SelectedItem { get { return _SelectedItem; } set { _SelectedItem = value; OnChanged(); } } } public class ViewModel : TreeViewModel<GroupModel> { private System.Collections.ObjectModel.ObservableCollection<GroupModel> _list = new System.Collections.ObjectModel.ObservableCollection<GroupModel>(); public System.Collections.ObjectModel.ObservableCollection<GroupModel> Items { get { return _list; } set { _list = value; OnChanged(); } } public ViewModel() { GroupModel groupModel1 = new GroupModel(); groupModel1.Name = "Ken"; GroupModel groupModel_1 = new GroupModel(); groupModel_1.Name = "A"; GroupModel groupModel_2 = new GroupModel(); groupModel_2.Name = "B"; GroupModel groupModel_3 = new GroupModel(); groupModel_3.Name = "C"; GroupModel groupModel_4 = new GroupModel(); groupModel_4.Name = "D"; groupModel1.Items.Add(groupModel_1); groupModel1.Items.Add(groupModel_2); groupModel1.Items.Add(groupModel_3); groupModel1.Items.Add(groupModel_4); GroupModel groupModel2 = new GroupModel(); groupModel2.Name = "TOM"; GroupModel groupModel_5 = new GroupModel(); groupModel_5.Name = "a"; GroupModel groupModel_6 = new GroupModel(); groupModel_6.Name = "b"; GroupModel groupModel_7 = new GroupModel(); groupModel_7.Name = "c"; GroupModel groupModel_8 = new GroupModel(); groupModel_8.Name = "d"; groupModel2.Items.Add(groupModel_5); groupModel2.Items.Add(groupModel_6); groupModel2.Items.Add(groupModel_7); groupModel2.Items.Add(groupModel_8); Items.Add(groupModel1); Items.Add(groupModel2); ModelChangedManger.Sub.Set(this); this.Accepted = true; } }
这样,就可以简单的实现了对selectedItem的变化的监控了