MVVMLight学习(三)Treeview树 节点增删修改后UI实时更新

项目场景:

最近在学习MVVM的过程中,本着学以致用的想法,便尝试着将曾经做过的一个项目以MVVM的方式重构一遍。


问题描述:

在开发过程中,项目使用了 Treeview 控件。在之前的实现过程中,控件树的源数据为 List<T> 类型,绑定在属性 ItemSource 上。若想实时更新 List 上的属性变化,需在类型T的定义过程中实现 INotifyPropertyChanged 接口,并在需要通知属性值变更的对应属性内实现类似 RaisePropertyChanged() 的方法。且在原来的开发中,没有实现对 List 内成员数量变化的时候的实时通知。

原实现方法:

Treeview.ItemSource = null;
Treeview.ItemSource = TreeviewNodes;

通过对控件绑定的源数据的“手动”更新去更新前台UI,不方便也很不科学


原因分析:

我们先看看 List 的定义:

    public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IEnumerable, IList, ICollection, IReadOnlyList<T>, IReadOnlyCollection<T>
    {...}

可以看出, List 本身是没有继承类似 Notify 的接口的,因此本身也无法提供属性改变的通知行为。


解决方案:

经过查找资料后,发现 .Net 提供了这样的一个集合类型 ObservableCollection<T>

	public class ObservableCollection<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged
    {...}

该类继承了继承了Collection, INotifyCollectionChanged, INotifyPropertyChanged,其中:

  • Collection:为泛型集合提供基类。

  • INotifyCollectionChanged:将集合的动态更改通知给侦听器,例如,何时添加和移除项或者重置整个集合对象。

  • INotifyPropertyChanged:向客户端发出某一属性值已更改的通知。

所以再ObservableCollection这个类的方法,对数据的操作很少,重点放在了当自己本事变化的时候(不管是属性,还是集合)会调用发出通知的事件。

下面贴出修改后的 Treeview 控件的实现代码

后台 ViewModel 中的代码:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using sdm.Model;

namespace sdm.ViewModel
{
	...
	
    public class MainViewModel : ViewModelBase
    {
		private ObservableCollection<NodeViewModel> treeviewNodes;
        /// <summary>
        /// TreeView
        /// </summary>
        public ObservableCollection<NodeViewModel> TreeviewNodes
        {
            get => treeviewNodes;
            set => Set(ref treeviewNodes, value);
        }
        
        public MainViewModel()
        {
            if (IsInDesignMode)
            {
                // Code runs in Blend --> create design time data.
            }
            else
            {
                // Code runs "for real"
            }  
            TreeviewNodes = new ObservableCollection<NodeViewModel>();
            
            //这里为了测试新增了5个测试节点
            for (int i = 0; i < 5; i++)
            {
                RtuModel rtu = new RtuModel();
                rtu.RtuNum = i;
                rtu.Address = $"测试节点{i}";
                NodeViewModel node = new NodeViewModel()
                {
                     Rtu = rtu,                     
                };

                TreeviewNodes.Add(node);
            }

        }
    }
}

前台 xaml 中的代码:

<TreeView Grid.Row="1" x:Name="treeview" Margin="10,5,10,0" ItemsSource="{Binding TreeviewNodes, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
	<TreeView.Resources>
		<HierarchicalDataTemplate  DataType="{x:Type vmmain:NodeViewModel}" ItemsSource="{Binding}">
			<StackPanel x:Name="SPanel" Orientation="Horizontal" Margin="0,2,0,2">
				<Image Height="15" Width="15" Source="{Binding ConIcon.Source, Mode=TwoWay}"/>
				<TextBlock x:Name="NodeText" Text="{Binding Title, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}"/>									
			</StackPanel>
		</HierarchicalDataTemplate>
 </TreeView>

运行后效果:
运行结果
实时新增节点:
运行结果
完美实现需求

参考资料:

[1] WPF MVVM-TreeView数据源添加了节点,UI没有刷新
[2] C# ObservableCollection和List的区别
[3] WPF中使用MVVM模式实现可动态检索的Treeview

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值