本系列文章导航
  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 (代码地址)

标签: none

添加新评论