zoukankan      html  css  js  c++  java
  • WPF之Treeview实现MVVM双向绑定

    Treeview分别有两个数据模板HierarchicalDataTemplate(层级数据模板)和DataTemplate(数据模板),分别应用于生成子数据项和普通数据项。
    在使用过程中,如果对两个模板的DataType设置为同一类型,运行时会直接报错。

    大概原因是添加了俩个相同Key的资源(因为HierarchicalDataTemplateDataTemplate都是定义在<TreeView.Resources>标签中)。
    代码:

    public class TypeTreeModel :TypeModel
    {
        public ObservableCollection<TypeTreeModel> ChildList { get; set; } 
            = new ObservableCollection<TypeTreeModel>();
    }
    public class TypeModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
    
    <TreeView x:Name="treeView" ItemsSource="{Binding TypeList}" MinWidth="200" MaxHeight="200" >
        <TreeView.Resources>
            <HierarchicalDataTemplate DataType="{x:Type vm:TypeTreeModel}" ItemsSource="{Binding ChildList}">
                <TextBlock Text="{Binding Name}" Margin="3 2"/>
            </HierarchicalDataTemplate>
            <DataTemplate DataType="{x:Type vm:TypeModel}">
                <TextBlock Text="{Binding Name}" ToolTip="{Binding Id}" Margin="3 2"></TextBlock>
            </DataTemplate>
        </TreeView.Resources>
    </TreeView>
    

    效果图:

    TypeList一般都是数据库取出来的数据处理嵌套后的结果。有时候会遇到需求,对于不同的分类有不同的类型。根据双向绑定的规则,我们只需要修改ViewModelTypeList的内容就可以了。

    注意: ObservableCollection只有在列表项发生变化时才会触发页面刷新,即新增或删除时才会反应到页面上。若采用直接赋值的写法,不会触发页面刷新。

    推荐更新数据时候的写法:

     //清空原先的列表
    TypeList.Clear();
    list.ForEach(d =>
    {
        TypeList.Add(d);
    });
    

    TreeView.SelectedItem双向绑定

    TreeView.SelectedItemReadOnly的,所以不能通过简单的绑定方法去获取选中项

    最终还是要通过绑定TreeviewSelectedItemChanged事件,来修改ViewModel中的数据
    1.直接绑定事件

    <TreeView ItemsSource="{Binding TypeList}" SelectedItemChanged="TreeView_OnSelectedItemChanged" />
    
    private void TreeView_OnSelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
    {
        vm.SelectItem = (Cluster)e.NewValue;
    }
    

    2.通过Command绑定事件

    • 在项目中引用 System.Windows.Interactivity.WPF(简单来说该插件可以将页面控件的Event转为ViewModel中的Command)
    • 在窗体中添加引用
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    
    • 绑定CommandSelectedItemChanged事件
    <TreeView x:Name="treeView" ItemsSource="{Binding TypeList}">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="SelectedItemChanged">
            <i:InvokeCommandAction Command="{Binding SelectItemChangeCommand}"
                   CommandParameter="{Binding ElementName=treeView,Path=SelectedItem}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    </TreeView>
    

    ViewModel:

    public class TreeViewModel : ViewModelBase
    {
        public ObservableCollection<TypeTreeModel> TypeList;
        
        private TypeModel selectItem;
        public TypeModel SelectItem
        {
            get { return selectItem; }
            set { this.MutateVerbose(ref selectItem, value, RaisePropertyChanged()); }
        }
        public TreeViewModel()
        {
            TypeList = GetData();
        }
    
        public ICommand SelectItemChangeCommand
        {
            get
            {
                return new CommandBase((param) => 
                {
                    if(param != null)
                        SelectItem = (TypeModel)param;
                });
            }
        }
    }
    

    效果图:

    ViewModelBaseCommandBase是自己封装的基类,就是为了写WPF的双向绑定简单点,有兴趣的可以评论向我要。
    Demo地址: https://github.com/fxhui/TreeViewDemo

  • 相关阅读:
    javascirpt Scoket
    黑马程序员面试题(一)交通灯管理系统
    中软国际实习总结
    黑马程序员Java基础正则表达式
    黑马程序员Java基础加强Java高新技术
    黑马程序员JAVA基础GUI
    面试题(二)银行业务调度系统
    黑马程序员JAVA基础IO流之File 类
    黑马程序员JAVA基础IO流其他类
    黑马程序员Java基础网络编程
  • 原文地址:https://www.cnblogs.com/cplemom/p/12078859.html
Copyright © 2011-2022 走看看