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

xml 复制代码
 <UserControl.DataContext>
     <viewModels:DemoViewModel />
 </UserControl.DataContext>
 <DockPanel>
     <StackPanel DockPanel.Dock="Bottom">
         <Button Command="{Binding AddItemCommand}"
                 Content="添加数据"></Button>

     </StackPanel>
     <DataGrid ItemsSource="{Binding People}"></DataGrid>
 </DockPanel>

Person

csharp 复制代码
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)));
}

ViewModel

csharp 复制代码
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();
    }

   
}

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

尝试老办法通知

csharp 复制代码
        public void AddItem()
        {
            People.Add(Models.Person.FakerOne);
            //没有效果
            //OnPropertyChanged(nameof(People));

            //没有效果
            //SetProperty(ref people, people);
        }

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

解决方案

ObservableCollection

简单的解决方案就是改成ObservableCollection,这里就不展开说明了。

但是有一个问题,这个ObservableCollection只在Count更新的时候触发自动更新。里面的Person值修改的时候是不会触发更新的。

如果有联动更新的需求,可以直接在【CollectionChanged】添加对应的代码

BindingList

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


ICollectionView

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

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

html 复制代码
<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>
csharp 复制代码
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);
        }

       
    }
}

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

csharp 复制代码
    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();
        }
    }

总结

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

相关推荐
Miqiuha12 分钟前
lock_guard和unique_lock学习总结
java·数据库·学习
一 乐1 小时前
学籍管理平台|在线学籍管理平台系统|基于Springboot+VUE的在线学籍管理平台系统设计与实现(源码+数据库+文档)
java·数据库·vue.js·spring boot·后端·学习
加油,旭杏2 小时前
【中间件学习】fastCG介绍和使用
学习·nginx·fastcgi
limengshi1383922 小时前
通信工程学习:什么是TFTP简单文件传输协议
网络·网络协议·学习·信息与通信
GFCGUO3 小时前
ubuntu18.04运行OpenPCDet出现的问题
linux·python·学习·ubuntu·conda·pip
丝丝不是土豆丝4 小时前
学习 CSS 新的属性 conic-gradient 实现环形进度条
学习
S hh4 小时前
【Linux】进程地址空间
java·linux·运维·服务器·学习
wusam5 小时前
螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习04(环境准备)
学习·docker·centos
攸攸太上5 小时前
Spring Gateway学习
java·后端·学习·spring·微服务·gateway
Geek之路6 小时前
QT系统学习篇(1)
开发语言·qt·学习