亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

WPF中MVVM模式的理解與實(shí)現(xiàn)

 更新時(shí)間:2024年05月29日 10:53:53   作者:mingupup  
MVVM是一種設(shè)計(jì)模式,特別適用于WPF(Windows Presentation Foundation)等XAML-based的應(yīng)用程序開(kāi)發(fā),MVVM模式主要包含三個(gè)部分:Model(模型)、View(視圖)和ViewModel(視圖模型),本文給大家介紹了WPF中MVVM模式的理解與實(shí)現(xiàn),需要的朋友可以參考下

MVVM模式的介紹

MVVM(Model-View-ViewModel)是一種設(shè)計(jì)模式,特別適用于WPF(Windows Presentation Foundation)等XAML-based的應(yīng)用程序開(kāi)發(fā)。MVVM模式主要包含三個(gè)部分:Model(模型)、View(視圖)和ViewModel(視圖模型)。

  1. Model(模型):模型代表的是業(yè)務(wù)邏輯和數(shù)據(jù)。它包含了應(yīng)用程序中用于處理的核心數(shù)據(jù)對(duì)象。模型通常包含業(yè)務(wù)規(guī)則、數(shù)據(jù)訪問(wèn)和存儲(chǔ)邏輯。
  2. View(視圖):視圖是用戶看到和與之交互的界面。在WPF中,視圖通常由XAML定義,并且包含各種用戶界面元素,如按鈕、文本框、列表等。
  3. ViewModel(視圖模型):視圖模型是視圖的抽象,它包含視圖所需的所有數(shù)據(jù)和命令。視圖模型通過(guò)實(shí)現(xiàn)INotifyPropertyChanged接口和使用ICommand對(duì)象,將視圖的狀態(tài)和行為抽象化,從而實(shí)現(xiàn)了視圖和模型的解耦。

MVVM模式的主要優(yōu)點(diǎn)是分離了視圖和模型,使得視圖和業(yè)務(wù)邏輯之間的依賴性降低,提高了代碼的可維護(hù)性和可測(cè)試性。此外,通過(guò)數(shù)據(jù)綁定和命令綁定,MVVM模式可以減少大量的樣板代碼,使得代碼更加簡(jiǎn)潔和易于理解。

image-20240527095704838

不使用MVVM模式的例子

要真正理解為什么要使用MVVM,使用MVVM有什么好處,肯定要與不使用MVVM的情況進(jìn)行對(duì)比。在Winform中我們使用了事件驅(qū)動(dòng)編程,同樣在WPF中我們也可以使用事件驅(qū)動(dòng)編程。

Windows Forms(WinForms)是一種基于事件驅(qū)動(dòng)的圖形用戶界面(GUI)框架。在WinForms中,用戶與應(yīng)用程序的交互主要通過(guò)事件來(lái)驅(qū)動(dòng)。

事件驅(qū)動(dòng)編程是一種編程范式,其中程序的執(zhí)行流程由外部事件(如用戶操作或系統(tǒng)事件)決定。在WinForms中,事件可以是用戶的各種操作,如點(diǎn)擊按鈕、選擇菜單項(xiàng)、輸入文本等,也可以是系統(tǒng)的事件,如窗口加載、大小改變等。

當(dāng)一個(gè)事件發(fā)生時(shí),會(huì)觸發(fā)與之關(guān)聯(lián)的事件處理器(Event Handler)。事件處理器是一個(gè)函數(shù)或方法,用于響應(yīng)特定的事件。例如,當(dāng)用戶點(diǎn)擊一個(gè)按鈕時(shí),可以觸發(fā)一個(gè)事件處理器,執(zhí)行一些特定的操作。

在WinForms中,你可以為各種控件添加事件處理器,以響應(yīng)用戶的操作。這種事件驅(qū)動(dòng)的方式使得你可以很容易地創(chuàng)建交互式的GUI應(yīng)用程序,而無(wú)需關(guān)心程序的執(zhí)行流程。

事件驅(qū)動(dòng)的簡(jiǎn)圖如下圖所示:

image-20240527100814935

  1. 事件源(Event Source):事件源是產(chǎn)生事件的對(duì)象。在WinForms中,事件源通常是用戶界面元素,如按鈕、文本框、菜單項(xiàng)等。當(dāng)用戶與這些元素進(jìn)行交互(如點(diǎn)擊按鈕、輸入文本等)時(shí),這些元素就會(huì)產(chǎn)生相應(yīng)的事件。
  2. 事件(Event):事件是由事件源產(chǎn)生的一個(gè)信號(hào),表示某種特定的事情已經(jīng)發(fā)生。例如,當(dāng)用戶點(diǎn)擊一個(gè)按鈕時(shí),按鈕就會(huì)產(chǎn)生一個(gè)Click事件。事件通常包含一些關(guān)于該事件的信息,例如事件發(fā)生的時(shí)間、事件的源對(duì)象等。
  3. 事件處理器(Event Handler):事件處理器是一個(gè)函數(shù)或方法,用于響應(yīng)特定的事件。當(dāng)一個(gè)事件發(fā)生時(shí),與該事件關(guān)聯(lián)的事件處理器就會(huì)被調(diào)用。在事件處理器中,你可以編寫代碼來(lái)定義當(dāng)事件發(fā)生時(shí)應(yīng)該執(zhí)行的操作。例如,你可以在按鈕的Click事件處理器中編寫代碼,定義當(dāng)用戶點(diǎn)擊按鈕時(shí)應(yīng)該執(zhí)行的操作。

現(xiàn)在我們通過(guò)一個(gè)例子在WPF中使用事件驅(qū)動(dòng)編程。

首先看一下我們的示例xaml頁(yè)面:

 <Window x:Class="WPF_MVVM_Pattern.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_MVVM_Pattern"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800"
        Loaded="Window_Loaded">
    <StackPanel>
        <ToolBar>
            <Label Content="姓名:"></Label>
            <TextBox x:Name="nameTextBox" Width="50"></TextBox>
            <Label Content="郵箱:"></Label>
            <TextBox x:Name="emailTextBox" Width="100"></TextBox>
            <Button Content="添加"
                    Click="AddUser"></Button>
       </ToolBar>
        <StackPanel>
            <DataGrid x:Name="dataGrid1"></DataGrid>
            
        </StackPanel>
    </StackPanel>
</Window>

image-20240527141918081

使用了兩個(gè)事件,分別是窗體加載事件:

Loaded="Window_Loaded"

與button點(diǎn)擊事件:

<Button Content="添加"
        Click="AddUser"></Button>

實(shí)現(xiàn)該操作與兩個(gè)類有關(guān):

 public class User
 {
     public string? Name { get; set; }
     public string? Email { get; set; }
 }
 public static class UserManager
 {
     public static ObservableCollection<User> DataBaseUsers = new       ObservableCollection<User>()
     {
         new User() { Name = "小王", Email = "123@qq.com" },
         new User() { Name = "小紅", Email = "456@qq.com" },
         new User() { Name = "小五", Email = "789@qq.com" }
     };

     public static ObservableCollection<User> GetUsers()
     {
         return DataBaseUsers;
     }

     public static void AddUser(User user)
     {
         DataBaseUsers.Add(user);
     }
 }

窗體加載事件處理程序:

 private void Window_Loaded(object sender, RoutedEventArgs e)
 {
    dataGrid1.ItemsSource =  UserManager.GetUsers();
 }

"添加"按鈕點(diǎn)擊事件處理程序:

 private void AddUser(object sender, RoutedEventArgs e)
 {
     User user = new User();
     user.Name = nameTextBox.Text;
     user.Email = emailTextBox.Text;
     UserManager.AddUser(user);
     MessageBox.Show("成功添加用戶!");
 }

實(shí)現(xiàn)的效果如下所示:

使用MVVM的例子

剛剛我們使用的是事件驅(qū)動(dòng)編程,我們?cè)趙inform開(kāi)發(fā)中經(jīng)常這樣干。對(duì)于一些小項(xiàng)目或者demo程序這樣做很方便,但是如果業(yè)務(wù)邏輯很多,這樣做就不好維護(hù),因?yàn)閁I與業(yè)務(wù)邏輯嚴(yán)重耦合了。

我們經(jīng)常在cs文件中使用xaml中的元素,也就是經(jīng)常在cs中引用xaml中的元素,如下所示:

image-20240527155929453

在C#代碼文件中直接引用XAML元素,會(huì)導(dǎo)致代碼與界面元素之間的耦合度增加,這是一種不良的編程實(shí)踐。以下是這種做法的一些潛在問(wèn)題:

  1. 耦合度高:代碼與界面元素緊密耦合,這使得代碼更難以維護(hù)和重用。如果你更改了界面元素(例如更改了元素的名稱或類型),你可能需要修改引用這個(gè)元素的所有代碼。
  2. 測(cè)試?yán)щy:由于代碼直接依賴于界面元素,這使得單元測(cè)試變得困難。你可能需要?jiǎng)?chuàng)建一個(gè)界面元素的實(shí)例,或者使用復(fù)雜的模擬技術(shù),才能測(cè)試這些代碼。
  3. 違反MVVM模式:在WPF中,推薦使用MVVM(Model-View-ViewModel)模式來(lái)組織代碼。在MVVM模式中,視圖(View)和模型(Model)之間的交互是通過(guò)視圖模型(ViewModel)來(lái)進(jìn)行的,而不是直接在代碼中引用界面元素。

開(kāi)始使用MVVM模式

RelayCommand

首先新建一個(gè)Commands文件夾,新建一個(gè)RelayComand類:

image-20240528084137467

RelayCommand如下:

public class RelayCommand : ICommand
{
  
    public event EventHandler? CanExecuteChanged;

    private Action<object> _Excute { get; set; }

    private Predicate<object> _CanExcute { get;set; }

    public RelayCommand(Action<object> ExcuteMethod, Predicate<object> CanExcuteMethod)
    {
        _Excute = ExcuteMethod;
        _CanExcute = CanExcuteMethod;
    }

    public bool CanExecute(object? parameter)
    {
       return _CanExcute(parameter);
    }

    public void Execute(object? parameter)
    {
       _Excute(parameter);
    }
}

RelayCommand實(shí)現(xiàn)了ICommand接口。

先來(lái)介紹一下ICommand接口。

ICommand

在WPF(Windows Presentation Foundation)中,ICommand是一個(gè)接口,它定義了一種機(jī)制,用于在用戶界面(UI)中處理事件,這種機(jī)制與用戶界面的具體行為進(jìn)行了解耦。這是實(shí)現(xiàn)MVVM(Model-View-ViewModel)設(shè)計(jì)模式的關(guān)鍵部分。

ICommand接口包含兩個(gè)方法和一個(gè)事件:

  • Execute(object parameter):當(dāng)調(diào)用此命令時(shí),應(yīng)執(zhí)行的操作。
  • CanExecute(object parameter):如果可以執(zhí)行Execute方法,則返回true;否則返回false。這可以用于啟用或禁用控件,例如按鈕。
  • CanExecuteChanged事件:當(dāng)CanExecute的返回值可能發(fā)生更改時(shí),應(yīng)引發(fā)此事件。

ICommand的結(jié)構(gòu)圖如下所示:

image-20240528084534354

代碼如下所示:

public interface ICommand
 {
  
     event EventHandler? CanExecuteChanged;
  
     bool CanExecute(object? parameter);
    
     void Execute(object? parameter);
 }

現(xiàn)在再來(lái)看看RelayCommand。

RelayCommand

RelayCommand是一種常用于WPF和MVVM模式的設(shè)計(jì)模式,它是一種特殊的命令類型。在MVVM模式中,RelayCommand允許將命令的處理邏輯從視圖模型中分離出來(lái),使得視圖模型不需要知道命令的具體執(zhí)行邏輯,從而實(shí)現(xiàn)了視圖模型和命令處理邏輯的解耦。

RelayCommand通常包含兩個(gè)主要部分:CanExecuteExecute。CanExecute是一個(gè)返回布爾值的函數(shù),用于確定命令是否可以執(zhí)行。Execute是一個(gè)執(zhí)行命令的函數(shù),當(dāng)CanExecute返回true時(shí),Execute將被調(diào)用。

這種設(shè)計(jì)模式使得你可以在不改變視圖模型的情況下,更改命令的處理邏輯,提高了代碼的可維護(hù)性和可重用性。

簡(jiǎn)單理解就是RelayCommandICommand接口的一個(gè)常見(jiàn)實(shí)現(xiàn),它允許你將ExecuteCanExecute的邏輯定義為委托,從而實(shí)現(xiàn)對(duì)命令的靈活處理。

在RelayCommand中我們定義了兩個(gè)委托:

private Action<object> _Excute { get; set; }

private Predicate<object> _CanExcute { get;set; }

Action<object>是一個(gè)委托,它封裝了一個(gè)接受單個(gè)參數(shù)并且沒(méi)有返回值的方法。這個(gè)參數(shù)的類型是object。

對(duì)應(yīng)于這一部分:

image-20240528085200268

Predicate<object>是一個(gè)委托,它封裝了一個(gè)接受單個(gè)參數(shù)并返回一個(gè)bool值的方法。這個(gè)參數(shù)的類型是object。

對(duì)應(yīng)于這一部分:

image-20240528085237548

RelayCommand的構(gòu)造函數(shù)為:

 public RelayCommand(Action<object> ExcuteMethod, Predicate<object> CanExcuteMethod)
 {
     _Excute = ExcuteMethod;
     _CanExcute = CanExcuteMethod;
 }

現(xiàn)在去看看View—ViewModel

View—ViewModel

ViewModel是一個(gè)抽象,它代表了View的狀態(tài)和行為。ViewModel包含了View所需的數(shù)據(jù),并提供了命令以響應(yīng)View上的用戶操作。ViewModel不知道View的具體實(shí)現(xiàn),它只知道如何提供View所需的狀態(tài)和行為。

ViewModel的主要職責(zé)包括:

  • 數(shù)據(jù)綁定:ViewModel提供了View所需的數(shù)據(jù)。這些數(shù)據(jù)通常是以屬性的形式提供的,當(dāng)這些屬性的值改變時(shí),ViewModel會(huì)通過(guò)實(shí)現(xiàn)INotifyPropertyChanged接口來(lái)通知View。
  • 命令綁定:ViewModel提供了命令以響應(yīng)View上的用戶操作。這些命令通常是以ICommand接口的實(shí)現(xiàn)的形式提供的。
  • 視圖邏輯:ViewModel包含了View的邏輯,例如,決定何時(shí)顯示或隱藏某個(gè)元素,何時(shí)啟用或禁用某個(gè)按鈕等。

新建一個(gè)ViewModel文件夾,在該文件夾中新建一個(gè)MainViewModel類:

image-20240528093058019

目前寫的MainViewModel如下:

public class MainViewModel
{
    public ObservableCollection<User> Users { get; set; }
    public ICommand AddUserCommand { get; set; }
    public string? Name { get; set; }
    public string? Email { get; set; }

    public MainViewModel()
    {
        Users = UserManager.GetUsers();
        AddUserCommand = new RelayCommand(AddUser, CanAddUser);
    }

    private bool CanAddUser(object obj)
    {
        return true;
    }

    private void AddUser(object obj)
    {
        User user = new User();
        user.Name = Name;
        user.Email = Email;
        UserManager.AddUser(user);
    }
}

現(xiàn)在我們結(jié)合這張圖,理解View與ViewModel之間的關(guān)系:

image-20240528093349406

一個(gè)一個(gè)來(lái)理解,首先最重要的就是數(shù)據(jù)綁定。

現(xiàn)在View的xaml如下:

<Window x:Class="WPF_MVVM_Pattern.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WPF_MVVM_Pattern"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <ToolBar>
            <Label Content="姓名:"></Label>
            <TextBox Text="{Binding Name}"  Width="50"></TextBox>
            <Label Content="郵箱:"></Label>
            <TextBox Text="{Binding Email}" Width="100"></TextBox>
            <Button Content="添加"
                    Command="{Binding AddUserCommand }"></Button>          
        </ToolBar>
        <StackPanel>
            <DataGrid ItemsSource="{Binding Users}"></DataGrid>
            
        </StackPanel>
    </StackPanel>
</Window>

cs如下:

public partial class MainWindow : Window
{      
    public MainWindow()
    {
        InitializeComponent();
        MainViewModel mainViewModel = new MainViewModel();
        this.DataContext = mainViewModel;
    }
   
}

將MainWindow的DataContext賦值給了mainViewModel。

 <TextBox Text="{Binding Name}"  Width="50"></TextBox>
 <TextBox Text="{Binding Email}" Width="100"></TextBox>
 <DataGrid ItemsSource="{Binding Users}"></DataGrid>

中進(jìn)行了數(shù)據(jù)綁定,對(duì)應(yīng)于圖中的這一部分:

image-20240528094205054

現(xiàn)在來(lái)看看命令綁定。

 <Button Content="添加"
         Command="{Binding AddUserCommand }"></Button>  

進(jìn)行了命令綁定,對(duì)應(yīng)于圖中這一部分:

image-20240528094348003

現(xiàn)在先來(lái)看看效果:

實(shí)現(xiàn)的效果

現(xiàn)在已經(jīng)實(shí)現(xiàn)了與前面基于事件驅(qū)動(dòng)同樣的效果,但是上面那張圖中的Send Notifications還沒(méi)有體現(xiàn)。

Send Notifications表示ViewModel中的更改會(huì)通知View。

現(xiàn)在我們來(lái)以一個(gè)例子說(shuō)明一下Send Notifications是如何實(shí)現(xiàn)的。

首先添加一個(gè)測(cè)試命令:

 public ICommand TestCommand { get; set; }

在構(gòu)造函數(shù)中添加:

 TestCommand = new RelayCommand(Test, CanTest);

實(shí)現(xiàn)Test與CanTest方法:

private bool CanTest(object obj)
{
    return true;
}

private void Test(object obj)
{
    Name = "小1";
    Email = "111@qq.com";
}

View中修改如下:

 <Button Content="測(cè)試"
         Command="{Binding TestCommand }"></Button>

現(xiàn)在去嘗試,我們會(huì)發(fā)現(xiàn)沒(méi)有效果,原因是我們的ViewModel沒(méi)有實(shí)現(xiàn)INotifyPropertyChanged接口。

INotifyPropertyChanged接口介紹

在WPF(Windows Presentation Foundation)中,INotifyPropertyChanged接口用于實(shí)現(xiàn)數(shù)據(jù)綁定中的屬性更改通知。當(dāng)綁定到UI元素的數(shù)據(jù)源中的屬性值發(fā)生更改時(shí),INotifyPropertyChanged接口可以通知UI元素更新。

INotifyPropertyChanged接口只定義了一個(gè)事件:PropertyChanged。當(dāng)屬性值發(fā)生更改時(shí),應(yīng)觸發(fā)此事件。事件參數(shù)PropertyChangedEventArgs包含更改的屬性的名稱。

現(xiàn)在我們的MainViewModel實(shí)現(xiàn)一下INotifyPropertyChanged接口,如下所示:

 public class MainViewModel : INotifyPropertyChanged
 {
     public ObservableCollection<User> Users { get; set; }
     public ICommand AddUserCommand { get; set; }
     public ICommand TestCommand { get; set; }

     private string? _name;
     public string? Name
     {
         get { return _name; }
         set
         {
             if (_name != value)
             {
                 _name = value;
                 OnPropertyChanged(nameof(Name));
             }
         }
     }

     private string? _email;
     public string? Email
     {
         get { return _email; }
         set
         {
             if (_email != value)
             {
                 _email = value;
                 OnPropertyChanged(nameof(Email));
             }
         }
     }

     public MainViewModel()
     {
         Users = UserManager.GetUsers();
         AddUserCommand = new RelayCommand(AddUser, CanAddUser);
         TestCommand = new RelayCommand(Test, CanTest);
     }

     private bool CanTest(object obj)
     {
         return true;
     }

     private void Test(object obj)
     {
         Name = "小1";
         Email = "111@qq.com";
     }

     private bool CanAddUser(object obj)
     {
         return true;
     }

     private void AddUser(object obj)
     {
         User user = new User();
         user.Name = Name;
         user.Email = Email;
         UserManager.AddUser(user);
     }

     public event PropertyChangedEventHandler? PropertyChanged;

     protected virtual void OnPropertyChanged(string propertyName)
     {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
     }
 }

現(xiàn)在再嘗試一下,會(huì)發(fā)現(xiàn)ViewModel中的更改會(huì)成功通知View了,如下所示:

對(duì)應(yīng)于圖中的這一部分:

image-20240528101649982

現(xiàn)在我們來(lái)看看ViewModel—Model。

ViewModel—Model

現(xiàn)在我們來(lái)看看ViewModel與Model之間的關(guān)系,可以根據(jù)下面這張圖進(jìn)行理解:

image-20240528101926207

Model(模型):Model代表了業(yè)務(wù)邏輯和數(shù)據(jù)。它包含了應(yīng)用程序中的數(shù)據(jù)和對(duì)數(shù)據(jù)的操作,例如,從數(shù)據(jù)庫(kù)中獲取數(shù)據(jù),或者向數(shù)據(jù)庫(kù)中添加數(shù)據(jù)。Model是獨(dú)立于UI的,它不知道UI的存在。

ViewModel(視圖模型):ViewModel是Model和View之間的橋梁。它包含了View所需的數(shù)據(jù)(這些數(shù)據(jù)來(lái)自于Model),并提供了命令以響應(yīng)View上的用戶操作。ViewModel將Model的數(shù)據(jù)轉(zhuǎn)換為View可以顯示的數(shù)據(jù),同時(shí),它也將View上的用戶操作轉(zhuǎn)換為對(duì)Model的操作。

在我們這個(gè)例子中我們的數(shù)據(jù)來(lái)源于Model文件夾下的User類與UserManager類:

image-20240528103959230

這里的Send Notifications又該如何理解呢?

我們也是以一個(gè)小例子進(jìn)行說(shuō)明。

首先將ViewModel中的Test方法修改為:

 private void Test(object obj)
 {
     Users[0].Name = "小1";
     Users[0].Email = "111@qq.com";
 }

會(huì)發(fā)現(xiàn)現(xiàn)在并不會(huì)發(fā)送通知,實(shí)現(xiàn)View上的修改,這是因?yàn)閁ser類并沒(méi)有實(shí)現(xiàn)INotifyPropertyChanged接口,現(xiàn)在修改User類實(shí)現(xiàn)INotifyPropertyChanged接口:

public class User : INotifyPropertyChanged
{
    private string? _name;
    public string? Name
    {
        get { return _name; }
        set
        {
            if (_name != value)
            {
                _name = value;
                OnPropertyChanged(nameof(Name));
            }
        }
    }

    private string? _email;
    public string? Email
    {
        get { return _email; }
        set
        {
            if (_email != value)
            {
                _email = value;
                OnPropertyChanged(nameof(Email));
            }
        }
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

現(xiàn)在可以實(shí)現(xiàn)通知了,效果如下所示:

使用MVVM庫(kù)

我們會(huì)發(fā)現(xiàn)如果全部都手動(dòng)實(shí)現(xiàn)MVVM模式的話,代碼有點(diǎn)多,有點(diǎn)麻煩。這時(shí)候就可以使用一些MVVM庫(kù)來(lái)簡(jiǎn)化我們的操作。

這里以CommunityToolkit.Mvvm為例,進(jìn)行說(shuō)明。

CommunityToolkit.Mvvm介紹

CommunityToolkit.Mvvm是Microsoft Community Toolkit的一部分,它是一個(gè)輕量級(jí)但功能強(qiáng)大的MVVM(Model-View-ViewModel)庫(kù),旨在幫助開(kāi)發(fā)者更容易地實(shí)現(xiàn)MVVM設(shè)計(jì)模式。

該庫(kù)提供了一些基礎(chǔ)類,如ObservableObjectObservableRecipient,這些類實(shí)現(xiàn)了INotifyPropertyChanged接口,并提供了SetProperty方法,可以在屬性值改變時(shí)觸發(fā)PropertyChanged事件。這使得數(shù)據(jù)綁定變得更加簡(jiǎn)單和高效。

此外,該庫(kù)還提供了ICommand接口的實(shí)現(xiàn),如RelayCommandAsyncRelayCommand,這些類可以幫助你創(chuàng)建命令,命令是MVVM模式中的一個(gè)重要組成部分。

CommunityToolkit.Mvvm還提供了一些其他有用的特性,如消息傳遞、設(shè)計(jì)時(shí)數(shù)據(jù)支持等,這些特性可以幫助你更好地組織和管理你的代碼。

CommunityToolkit.Mvvm是一個(gè)強(qiáng)大的工具,它可以幫助你更容易地實(shí)現(xiàn)MVVM模式,從而提高你的代碼質(zhì)量和開(kāi)發(fā)效率。

image-20240528112612211

修改之后的ViewModel如下所示:

 public partial class MainViewModel : ObservableObject
 {
     public ObservableCollection<User> Users { get; set; }    

     [ObservableProperty]
     private string? name;

     [ObservableProperty]
     private string? email;
    

     public MainViewModel()
     {
         Users = UserManager.GetUsers();         
     }
  
     [RelayCommand]
     private void Test(object obj)
     {
         Users[0].Name = "小1";
         Users[0].Email = "111@qq.com";
     }
    
     [RelayCommand]
     private void AddUser(object obj)
     {
         User user = new User();
         user.Name = Name;
         user.Email = Email;
         UserManager.AddUser(user);
     }
    
 }

修改之后的User類如下所示:

 public partial class User : ObservableObject
 {
     [ObservableProperty]
     private string? _name;

     [ObservableProperty]
     private string? _email;            
 }

用到了CommunityToolkit.Mvvm庫(kù)中的三個(gè)東西,分別是ObservableObject、[ObservableProperty]與[RelayCommand]。

先來(lái)看一下ObservableObject。

ObservableObjectCommunityToolkit.Mvvm庫(kù)中的一個(gè)基礎(chǔ)類,它實(shí)現(xiàn)了INotifyPropertyChanged接口。這個(gè)接口是.NET數(shù)據(jù)綁定基礎(chǔ)架構(gòu)的一部分,當(dāng)對(duì)象的一個(gè)屬性改變時(shí),它會(huì)通知綁定到該屬性的任何元素。

image-20240528120932293

image-20240528121004023

具體見(jiàn):ObservableObject - Community Toolkits for .NET | Microsoft Learn

在這里我們使用

 [ObservableProperty]
 private string? name;

它將生成一個(gè)像這樣的可觀察屬性:

public string? Name
{
    get => name;
    set => SetProperty(ref name, value);
}

具體見(jiàn):ObservableProperty attribute - Community Toolkits for .NET | Microsoft Learn

我們使用

[RelayCommand]
private void AddUser(object obj)
{
   User user = new User();
   user.Name = Name;
   user.Email = Email;
   UserManager.AddUser(user);
}

代碼生成器會(huì)生成一個(gè)命令如下所示:

private RelayCommand? addUserCommand;

public IRelayCommand AddUserCommand => addUserCommand ??= new RelayCommand(AddUser);

具體見(jiàn):RelayCommand attribute - Community Toolkits for .NET | Microsoft Learn

現(xiàn)在我們的ViewModel與Model就可以簡(jiǎn)化了,現(xiàn)在再來(lái)看看效果:

總結(jié)

本文先總體介紹了一下MVVM模式,關(guān)于MVVM模式可以根據(jù)這張圖幫助理解:

image-20240527095704838

由于很多同學(xué)可能與我一樣,是從winform到wpf的,因此在wpf中使用winform中的事件驅(qū)動(dòng)編程范式完成了一個(gè)小例子,關(guān)于事件驅(qū)動(dòng)編程,可以根據(jù)這張圖幫助理解:

image-20240527100814935

由于這種模式耦合比較多,我們想要松耦合,因此開(kāi)始學(xué)習(xí)MVVM模式。我們創(chuàng)建了實(shí)現(xiàn)ICommand接口的RelayCommand類,實(shí)現(xiàn)INotifyPropertyChanged接口的MainViewModel類與User類。使用數(shù)據(jù)綁定與命令綁定改寫xaml頁(yè)面。

最后由于手動(dòng)實(shí)現(xiàn)MVVM模式,需要寫很多代碼,看過(guò)去比較復(fù)雜與麻煩,我們可以使用MVVM庫(kù)來(lái)簡(jiǎn)化MVVM模式的實(shí)現(xiàn)。

以上就是WPF中MVVM模式的理解與實(shí)現(xiàn)的詳細(xì)內(nèi)容,更多關(guān)于WPF MVVM模式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C#中圖片的Base64編碼與解碼轉(zhuǎn)換詳解

    C#中圖片的Base64編碼與解碼轉(zhuǎn)換詳解

    在C#中,我們可以使用Base64編碼將圖片轉(zhuǎn)換為字符串,也可以將Base64編碼的字符串轉(zhuǎn)換回圖片,這通常用于在需要文本表示圖像數(shù)據(jù)的場(chǎng)合(例如在Web開(kāi)發(fā)中傳輸圖像數(shù)據(jù)),本文介紹了C#中圖片的Base64編碼與解碼轉(zhuǎn)換,需要的朋友可以參考下
    2024-12-12
  • unity shader實(shí)現(xiàn)較完整光照效果

    unity shader實(shí)現(xiàn)較完整光照效果

    這篇文章主要為大家詳細(xì)介紹了unity shader實(shí)現(xiàn)較完整光照效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • C#文件路徑Path類介紹

    C#文件路徑Path類介紹

    這篇文章介紹了C#中的文件路徑Path類,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2022-05-05
  • C#控制臺(tái)下測(cè)試多線程的方法

    C#控制臺(tái)下測(cè)試多線程的方法

    這篇文章主要介紹了C#控制臺(tái)下測(cè)試多線程的方法,涉及C#操作多線程的技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2015-04-04
  • C#事件用法實(shí)例淺析

    C#事件用法實(shí)例淺析

    這篇文章主要介紹了C#事件用法,以實(shí)例形式分析了C#中事件的定義、觸發(fā)及處理相關(guān)技巧,需要的朋友可以參考下
    2015-05-05
  • 再議C#中的裝箱與拆箱的問(wèn)題詳解

    再議C#中的裝箱與拆箱的問(wèn)題詳解

    本篇文章再次介紹了C#中的裝箱與拆箱,這次們看下使用泛型和不使用泛型引發(fā)裝箱拆箱的情況
    2013-05-05
  • C#實(shí)現(xiàn)自定義動(dòng)畫鼠標(biāo)的示例詳解

    C#實(shí)現(xiàn)自定義動(dòng)畫鼠標(biāo)的示例詳解

    這篇文章主要為大家詳細(xì)介紹了如何利用C#實(shí)現(xiàn)自定義動(dòng)畫鼠標(biāo)效果,文中的示例代碼講解詳細(xì),對(duì)我們學(xué)習(xí)C#有一定的幫助,感興趣的小伙伴可以跟隨小編一起了解一下
    2022-12-12
  • c++ STL之list對(duì)結(jié)構(gòu)體的增加,刪除,排序等操作詳解

    c++ STL之list對(duì)結(jié)構(gòu)體的增加,刪除,排序等操作詳解

    這篇文章主要介紹了c++ STL之list對(duì)結(jié)構(gòu)體的增加,刪除,排序等操作詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-12-12
  • 關(guān)于C# TabPage如何隱藏的問(wèn)題

    關(guān)于C# TabPage如何隱藏的問(wèn)題

    TabPage沒(méi)有Visible屬性,所以只能通過(guò)設(shè)置將其與父控件(tabcontrol)的關(guān)聯(lián)性去除就好了,如下面代碼:
    2013-04-04
  • C#實(shí)現(xiàn)將商品金額小寫轉(zhuǎn)換成大寫的方法

    C#實(shí)現(xiàn)將商品金額小寫轉(zhuǎn)換成大寫的方法

    這篇文章主要介紹了C#實(shí)現(xiàn)將商品金額小寫轉(zhuǎn)換成大寫的方法,涉及C#數(shù)組與字符串的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下
    2016-08-08

最新評(píng)論