CommunityToolkit.Mvvm8.1 viewmodel源生成器寫法(3)

2023-04-11 15:00:51

 

本系列文章導航
  1. https://www.cnblogs.com/aierong/p/17300066.html
  2. https://github.com/aierong/WpfDemo (自我Demo地址)


希望提到的知識對您有所提示,同時歡迎交流和指正
作者:aierong
出處:https://www.cnblogs.com/aierong

 

說明

CommunityToolkit.Mvvm8.1最令人驚喜的是它提供的源生成器功能,它極大簡化我們的mvvm程式碼
我們通過標記一個屬性就可以實現某個功能,這個很方便快捷,推薦

常用標記總結
1.繼承ObservableObject 並且類標記是分部類partial
2.私有變數標記屬性 [ObservableProperty]
3.NotifyCanExecuteChangedFor  通知依賴命令
  NotifyPropertyChangedFor    通知依賴屬性
4.RelayCommand  定義命令
5.OnPropertyChanged 手動通知屬性更新
6.ButtonClickCommand.NotifyCanExecuteChanged() 手動通知命令更新
7.OnLastNameChanging OnLastNameChanged  某個屬性改變
8.OnPropertyChanged  所有屬性改變

 

定義viewmodel

定義vm時,請使用分部類,並且繼承ObservableObject

public partial class DataViewModel2 : ObservableObject
{

}

 

ObservableProperty標記屬性

定義屬性如此簡單:一個[ObservableProperty]標記搞定

/*
[ObservableProperty]標記後,會自動生成屬性(大寫命名),例如:下面會自動生成Title

注意:這個私有變數命名:必須是小寫開頭,或者下劃線,或者m_
*/

[ObservableProperty]
private string title = "hello";

//public string Title
//{
//    get
//    {
//        return title;
//    }
//    set
//    {
//        //title = value;
//        //PropertyChanged?.Invoke( this , new PropertyChangedEventArgs( "Name" ) );

//        //SetProperty 相當與設定值,並且PropertyChanged通知呼叫
//        SetProperty( ref title , value );
//    }
//}

 

NotifyPropertyChangedFor通知依賴屬性

[NotifyPropertyChangedFor( nameof( Caption ) )]標識:在LastName改變後,去通知Caption

public string Caption
{
    get
    {
        return string.Format( "Title:{0}-{1}" , Title , LastName );
    }
}


[ObservableProperty]
[NotifyPropertyChangedFor( nameof( Caption ) )]
private string lastName = "abc";

 

NotifyCanExecuteChangedFor通知依賴命令

在屬性IsEnabled改變後,通知命令:ButtonClickCommand

/*
        [NotifyCanExecuteChangedFor( nameof( ButtonClickCommand ) )]
NotifyCanExecuteChangedFor是通知依賴命令(觸發命令),相當於set中ButtonClickCommand.NotifyCanExecuteChanged();
*/

[ObservableProperty]
[NotifyCanExecuteChangedFor( nameof( ButtonClickCommand ) )]
private bool isEnabled = false;

//public bool IsEnabled
//{
//    get => isEnabled;
//    set
//    {
//        SetProperty( ref isEnabled , value );

//        //通知命令 已經改變
//        ButtonClickCommand.NotifyCanExecuteChanged();
//    }
//}

//partial void OnIsEnabledChanged ( bool value )
//{
//     //如果上面的[NotifyCanExecuteChangedFor( nameof( ButtonClickCommand ) )]不寫,可以這裡手動通知更新 
//    //ButtonClickCommand.NotifyCanExecuteChanged();
//}

 

 

命令

RelayCommand標識定義一個命令,如此簡單

/*
RelayCommand是定義命令,自動生成的命令名是方法名+Command,並且初始化
例如:下面的會自動生成ButtonClickCommand

CanExecute是指定一個判斷方法,判斷是否可用
*/

[RelayCommand( CanExecute = nameof( CanButton ) )]
void ButtonClick ()
{
    //點選按鈕,修改標題
    Title = "hello(改)";
}

bool CanButton ()
{
    return IsEnabled;
}

//public RelayCommand ButtonClickCommand
//{
//    get;
//}



[RelayCommand]
void ButtonClickPar ( double val )
{
    Title = $"hello(改):{val}";
}

//public RelayCommand<double> ButtonClickParCommand
//{
//    get;
//}

 

 

非同步命令

把方法標識為async,即可定義為非同步命令,它帶有一個IsRunning屬性,可以在view中做進度條判斷

[RelayCommand]
async Task AsyncButtonClick ()
{
    await Task.Delay( 4800 );
    Title = "hello(Task改)";
}



[RelayCommand]
async Task AsyncButtonParClick ( double val )
{
    await Task.Delay( 4800 );
    Title = $"hello(Task改):{val}";
}
<!--   
特別說明:非同步命令會自動控制控制元件的可見性,並且提供一個IsRunning屬性可以判斷非同步是否完成   
-->
<Button Width="100"
        Height="30"
        Command="{Binding AsyncButtonClickCommand}"
        Content="非同步" />
<TextBlock HorizontalAlignment="Center"
           FontSize="20"
           FontStyle="Italic"
           FontWeight="Bold"
           Foreground="Green"
           Text="loading......"
           Visibility="{Binding AsyncButtonClickCommand.IsRunning, Converter={StaticResource myboolconvert}}" />

 

某個屬性改變

On+屬性Changing  On+屬性Changed,可以記錄某個屬性值變化事件

/*
還可以實現2個方法:OnLastNameChanging OnLastNameChanged (注意2個方法只可以實現其中一個,或者都不實現(不能同時2個))
*/

//partial void OnLastNameChanging ( string value )
//{
//    Debug.WriteLine( value );
//}

partial void OnLastNameChanged ( string value )
{
    // 可以做一些其它事情 例如:屬性改變後,訊息通知某某某
    Debug.WriteLine( value );



    //說明:如果上面[NotifyPropertyChangedFor( nameof( Caption ) )]不寫,可以這裡手動通知屬性更新
    //OnPropertyChanged( nameof( Caption ) );
}

 

所有屬性改變

所有屬性改變後都會呼叫這個事件,引數PropertyName可以區分具體哪個屬性

/// <summary>
/// 所有屬性改變
/// </summary>
/// <param name="e"></param>
protected override void OnPropertyChanged ( PropertyChangedEventArgs e )
{

    base.OnPropertyChanged( e );

    // 可以獲取到是哪個屬性改變了
    var _proname = e.PropertyName;
}

 

完整程式碼

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;

/*
這裡演示自動生成屬性和命令

1.繼承ObservableObject 並且類標記是分部類partial
2.私有變數標記屬性 [ObservableProperty]
3.NotifyCanExecuteChangedFor  通知依賴命令
  NotifyPropertyChangedFor    通知依賴屬性
4.RelayCommand  定義命令
5.OnPropertyChanged 手動通知屬性更新
6.ButtonClickCommand.NotifyCanExecuteChanged() 手動通知命令更新
7.OnLastNameChanging OnLastNameChanged  某個屬性改變
8.OnPropertyChanged  所有屬性改變
*/

namespace WpfDemoNet6.Demo
{
    public partial class DataViewModel2 : ObservableObject
    {
        /*
        [ObservableProperty]標記後,會自動生成屬性(大寫命名),例如:下面會自動生成Title

        注意:這個私有變數命名:必須是小寫開頭,或者下劃線,或者m_
        */

        /*
        NotifyPropertyChangedFor 通知依賴屬性Caption
        */

        [ObservableProperty]
        [NotifyPropertyChangedFor( nameof( Caption ) )]
        private string title = "hello";

        //public string Title
        //{
        //    get
        //    {
        //        return title;
        //    }
        //    set
        //    {
        //        //title = value;
        //        //PropertyChanged?.Invoke( this , new PropertyChangedEventArgs( "Name" ) );

        //        //SetProperty 相當與設定值,並且PropertyChanged通知呼叫
        //        SetProperty( ref title , value );
        //    }
        //}


        /*
                [NotifyCanExecuteChangedFor( nameof( ButtonClickCommand ) )]
        NotifyCanExecuteChangedFor是通知依賴命令(觸發命令),相當於set中ButtonClickCommand.NotifyCanExecuteChanged();
        */

        [ObservableProperty]
        [NotifyCanExecuteChangedFor( nameof( ButtonClickCommand ) )]
        private bool isEnabled = false;

        //public bool IsEnabled
        //{
        //    get => isEnabled;
        //    set
        //    {
        //        SetProperty( ref isEnabled , value );

        //        //通知命令 已經改變
        //        ButtonClickCommand.NotifyCanExecuteChanged();
        //    }
        //}

        //partial void OnIsEnabledChanged ( bool value )
        //{
        //     //如果上面的[NotifyCanExecuteChangedFor( nameof( ButtonClickCommand ) )]不寫,可以這裡手動通知更新 
        //    //ButtonClickCommand.NotifyCanExecuteChanged();
        //}




        /*
        RelayCommand是定義命令,自動生成的命令名是方法名+Command,並且初始化
        例如:下面的會自動生成ButtonClickCommand

        CanExecute是指定一個判斷方法,判斷是否可用
        */

        [RelayCommand( CanExecute = nameof( CanButton ) )]
        void ButtonClick ()
        {
            //點選按鈕,修改標題
            Title = "hello(改)";
        }

        bool CanButton ()
        {
            return IsEnabled;
        }

        //public RelayCommand ButtonClickCommand
        //{
        //    get;
        //}



        public DataViewModel2 ()
        {
            //RelayCommand的第一個引數是命令呼叫語句
            //              第2個引數(可選)是否允許使用
            //ButtonClickCommand = new RelayCommand( () =>
            //{
            //    //點選按鈕,修改標題
            //    Title = "hello(改)";
            //} , () =>
            //{
            //    return IsEnabled;
            //} );

            //ButtonClickParCommand = new RelayCommand<double>( ( double val ) =>
            //{
            //    Title = $"hello(改):{val}";
            //} );
        }



        [RelayCommand]
        void ButtonClickPar ( double val )
        {
            Title = $"hello(改):{val}";
        }

        //public RelayCommand<double> ButtonClickParCommand
        //{
        //    get;
        //}



        public string Caption
        {
            get
            {
                return string.Format( "Title:{0}-{1}" , Title , LastName );
            }
        }


        [ObservableProperty]
        [NotifyPropertyChangedFor( nameof( Caption ) )]
        private string lastName = "abc";

        /*
        還可以實現2個方法:OnLastNameChanging OnLastNameChanged (注意2個方法只可以實現其中一個,或者都不實現(不能同時2個))
        */

        //partial void OnLastNameChanging ( string value )
        //{
        //    Debug.WriteLine( value );
        //}

        partial void OnLastNameChanged ( string value )
        {
            // 可以做一些其它事情 例如:屬性改變後,訊息通知某某某
            Debug.WriteLine( value );



            //說明:如果上面[NotifyPropertyChangedFor( nameof( Caption ) )]不寫,可以這裡手動通知屬性更新
            //OnPropertyChanged( nameof( Caption ) );
        }



        /// <summary>
        /// 所有屬性改變
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPropertyChanged ( PropertyChangedEventArgs e )
        {

            base.OnPropertyChanged( e );

            // 可以獲取到是哪個屬性改變了
            var _proname = e.PropertyName;
        }

    }
}

 

導航

https://github.com/aierong/WpfDemo/tree/main/WpfDemoNet6 (專案地址)

https://github.com/aierong/WpfDemo/blob/main/WpfDemoNet6/Demo/DataViewModel2.cs (程式碼地址)