• WPF 【十月的寒流】学习笔记(2):MVVM中是怎么实现通知的


    前言

    我们这次详细了解一下列表通知的底层是怎么实现的

    相关链接

    十月的寒流

    在这里插入图片描述
    在这里插入图片描述

    MVVM实战技巧之:可被观测的集合(ObservableCollection & BindingList)

    代码仓库

    我为了方便展示源代码,我将代码提交到了代码仓库里面

    B站【十月的寒流】对应课程的代码 Github仓库

    项目配置

    如何使用我这里就不展开说明了

    WPF CommunityToolkit.Mvvm

    WPF CommunityToolkit.Mvvm Messenger通讯

    在这里插入图片描述

    WPF-UI HandyControl 简单介绍

    WPF-UI HandyControl 控件简单实战+IconPacks矢量图导入

    在这里插入图片描述

    Bogus,.NET生成批量模拟数据
    在这里插入图片描述

    代码

    初始代码

    View

     <UserControl.DataContext>
         <viewModels:DemoViewModel />
     UserControl.DataContext>
     <DockPanel>
         <StackPanel DockPanel.Dock="Bottom">
             <Button Command="{Binding AddItemCommand}"
                     Content="添加数据">Button>
    
         StackPanel>
         <DataGrid ItemsSource="{Binding People}">DataGrid>
     DockPanel>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    Person

    public class Person
    {
        public int Id { get; set; }
    
        public string FirstName { get; set; }
    
        public string LastName { get; set; }
    
        public string FullName { get; set; }
    
        public DateOnly BirthDay { get; set; }
    
        public static Person FakerOne => faker.Generate();
    
        public static IEnumerable<Person> FakerMany(int count)=>faker.Generate(count);
    
        private static readonly Faker<Person> faker = new Faker<Person>()
            .RuleFor(t=>t.Id,f=>f.IndexFaker)
            .RuleFor(t=>t.FirstName,f=>f.Name.FirstName())
            .RuleFor(t=>t.LastName,f=>f.Name.LastName())
            .RuleFor(t=>t.FullName,f=>f.Name.FullName())
            .RuleFor(t=>t.BirthDay,f=>f.Date.BetweenDateOnly(new DateOnly(1990,1,1),new DateOnly(2010,1,1)));
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    ViewModel

    public partial class DemoViewModel:ObservableObject
    {
        [ObservableProperty]
        private List<Models.Person> people = new List<Models.Person>();
    
        [RelayCommand]
        public void AddItem()
        {
            People.Add(Models.Person.FakerOne);
        }
    
        public DemoViewModel() {
            People = Models.Person.FakerMany(5).ToList();
        }
    
       
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    现在的代码是没有实现通知,点击按钮也不会添加

    在这里插入图片描述

    尝试老办法通知

            public void AddItem()
            {
                People.Add(Models.Person.FakerOne);
                //没有效果
                //OnPropertyChanged(nameof(People));
    
                //没有效果
                //SetProperty(ref people, people);
            }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    而且在我们点击ListBox的时候,会报错。这个就说明,其实List已经修改了,但是这个通知方法不行。原因是List指向的是一个地址空间,这个地址空间并没有变化。
    在这里插入图片描述

    解决方案

    ObservableCollection

    简单的解决方案就是改成ObservableCollection,这里就不展开说明了。
    在这里插入图片描述
    但是有一个问题,这个ObservableCollection只在Count更新的时候触发自动更新。里面的Person值修改的时候是不会触发更新的。

    如果有联动更新的需求,可以直接在【CollectionChanged】添加对应的代码
    在这里插入图片描述

    BindingList

    这里我就不展开说明了,直接上视频的源代码了。

    在这里插入图片描述
    在这里插入图片描述

    ICollectionView

    WPF 【十月的寒流】学习笔记(1):DataGrid过滤

    更好的解决方案就是直接更新。我们直接刷新ItemSorce

    <UserControl x:Class="WpfMvvmDemo.Views.DemoView"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
                 xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
                 xmlns:local="clr-namespace:WpfMvvmDemo.Views"
                 xmlns:viewModels="clr-namespace:WpfMvvmDemo.ViewModels"
                 mc:Ignorable="d"
                 d:DesignHeight="450"
                 d:DesignWidth="800">
        <UserControl.DataContext>
            <viewModels:DemoViewModel />
        UserControl.DataContext>
        <DockPanel>
            <StackPanel DockPanel.Dock="Bottom"
                        HorizontalAlignment="Left"
                        Orientation="Horizontal">
                <Button Command="{Binding AddItemCommand}"
                        Margin="5"
                        Content="添加数据">Button>
                <Button Command="{Binding UpIdCommand}"
                        Margin="5"
                        Content="增加Id">Button>
            StackPanel>
            <DataGrid ItemsSource="{Binding PeopleView}">DataGrid>
        DockPanel>
    UserControl>
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    using Bogus;
    using CommunityToolkit.Mvvm.ComponentModel;
    using CommunityToolkit.Mvvm.Input;
    using System;
    using System.Collections.Generic;
    using System.Collections.Specialized;
    using System.ComponentModel;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows.Data;
    
    namespace WpfMvvmDemo.ViewModels
    {
        public partial class DemoViewModel:ObservableObject
        {
            [ObservableProperty]
            private List<Models.Person> people = new List<Models.Person>();
    
            [ObservableProperty]
            private ICollectionView peopleView;
    
            [RelayCommand]
            public void AddItem()
            {
                People.Add(Models.Person.FakerOne);
                //没有效果
                //OnPropertyChanged(nameof(People));
    
                //没有效果
                //SetProperty(ref people, people);
    
                //直接更新整个视图源
                PeopleView.Refresh();
                
            }
            [RelayCommand]
            public void UpId()
            {
                foreach (var item in People)
                {
                    item.Id += 10;
                }
                PeopleView.Refresh();
            }
    
            public DemoViewModel() {
                People = Models.Person.FakerMany(5).ToList();
                PeopleView = CollectionViewSource.GetDefaultView(People);
            }
    
           
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    为了方便,我们也可以直接新建一个类,这里就把代码放一下,就不展开说明了

        public class CollectionData<T> where T : class
        {
    
            public IEnumerable<T> Data { get; set; }
    
            public ICollectionView CollectionView { get; set; }
            public CollectionData() { }
    
            public void Init()
            {
                CollectionView = CollectionViewSource.GetDefaultView(Data);
                CollectionView.Refresh();
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    总结

    我觉得当时【十月的寒流】那个视频一直在想用MVVM去通知更新,当然他的主题也是使用MVVM自动更新。但是ItemSorce随时都有可能发生修改。要么就是每次事件之后修改,要么就给每个可能会触发的属性添加通知。

  • 相关阅读:
    C++中的fsanitize指令
    基于ubuntu1604的ROS安装
    Visual Studio中的四款代码格式化工具
    数据治理-度量指标
    实现一个简单的 ctrl+ f 搜索
    详解c++---入门(上)
    select下拉菜单自由扩展-输入框添加/options删除
    删除元素(带过渡动画)
    CO01,CO07结算规则增强
    HTML5+CSS3+JS小实例:霁青+翠蓝的Tabbar动画特效
  • 原文地址:https://blog.csdn.net/qq_44695769/article/details/136310245