首页 > 其他分享 >WPF TreeView 检测SelectedItem变化的简单方案

WPF TreeView 检测SelectedItem变化的简单方案

时间:2023-07-14 10:55:41浏览次数:40  
标签:Items GroupModel private groupModel SelectedItem new WPF TreeView public

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的变化的监控了

源代码连接

标签:Items,GroupModel,private,groupModel,SelectedItem,new,WPF,TreeView,public
From: https://www.cnblogs.com/T-ARF/p/17553107.html

相关文章

  • WPF获取MainWindows实例
    WPF获取MainWindow实例在其他类中获取MainWindow实例,获取其控件,改变其控件属性等,代码如下:_mainWindow=Application.Current.Windows.Cast<Window>().FirstOrDefault(Window=>WindowisMainWindow)asMainWindow;例如在ConfigureViewModel中改变MainWindow中的某个TextB......
  • WPF开发中ReactiveUI.Fody的使用
    前面的开发一般我会使用PropertyChanged.Fody,但ReactiveUI.Fody也能实现类似的功能。安装Nuget包Install-PackageReactiveUI.FodyFodyWeavers.xml文件:<Weaversxmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:noNamespaceSchemaLocation="FodyWeavers.xsd"......
  • 管理员权限启动WPF应用程序
    1、添加应用程序清单文件 2、requestedExecutionLevel节点,level属性修改为“requireAdministrator”<requestedExecutionLevellevel="requireAdministrator"uiAccess="false"/> ......
  • WPF border解决超出圆角边界的方法
    使用Border并设置圆角,Border内部的其他元素会超出圆角而导致灾难级的视觉体验,通过设置Border的clip属性,来解决这个问题<BorderBorderThickness="1"BorderBrush="Black"CornerRadius="8"><Border.Clip>......
  • WPF快速定位某个元素的相关信息
    运行起WPF程序,使用以下方式,可以快速定位某个元素的信息:1、在运行的程序页面上面选中以下圈中按钮  2、点击上图2处,在界面上选中需要查看的按钮,或者文字等  3、点击界面上方第一个按钮“转为实时可视化树”,然后进入VS界面,查看左侧的树结构 4、在VS中的可视化树中,......
  • 跨平台GUI开发技术:QT,GTK+, C#(WinForm/WPF), Java(Swing/AWT/JavaFX), Electron, comp
    1.Compose-multiplatformJetbrian推出的跨全平台开发组件技术,android/ios/desktop(win,linux,mac)/web,目前生态完善中,还不够成熟,但有潜力,支持原生接口调用,kotlin作为主要语言。https://www.jetbrains.com/zh-cn/lp/compose-multiplatformhttps://github.com/JetBrains/compose-......
  • 界面控件DevExpress WPF数据编辑器,让数据处理更灵活!(一)
    界面控件DevExpressWPF编辑器库可以帮助用户提供直观的用户体验,具有无与伦比的运行时选项和灵活性。WPF数据编辑器提供了全面的掩码和数据验证支持,可以独立使用,也可以作为容器控件(如DevExpressWPFGrid和WPFTreeList)中的单元格编辑器使用。DevExpressWPF拥有120+个控件和库......
  • Winform和WPF检查应用是否重复打开
    一、以App扩展方法检查进程名和进程ID的方式1PublicstaticTSetSingleProcess(thisTapp)WhereT:Application2{3varprocess=Process.GetProcesses().Where(p=>p.ProcessNames==Process.GetCurrentProcess().ProcessName&&p.Id!=Process.GetCurrentProcess().Id)......
  • AvaloniaUI 和 WPF 图形性能的简单测试.
     本文发布于:https://www.cnblogs.com/8u7tgyjire7890/p/17545599.html 原始代码来自于 Avalonia 示例程序https://github.com/AvaloniaUI/Avalonia/blob/master/samples/ControlCatalog/Pages/CustomDrawing.xaml.cs我将其修改为一个单独的Avalonia应用程序,同时将其翻......
  • wpf的动态Tab的例子,使用Prism
    引用Prism.Core,Prism.Wpf和Prism.Unity修改App.xaml的类型替换为 PrismApplication 修改App.xaml.cs:///<summary>///InteractionlogicforApp.xaml///</summary>publicpartialclassApp:PrismApplication{protectedoverride......