• C#语法——消息,MVVM的核心技术。


    在C#中消息有两个指向,一个指向Message,一个指向INotify。这里主要讲INotify。

    INotify也有人称之为[通知],不管叫消息还是通知,都是一个意思,就是传递信息。

    消息的定义

    INotify消息其实是一个接口,接口名叫INotifyPropertyChanged。接口定义如下:

     //向客户端发出某一属性值已更改的通知。
     public interface INotifyPropertyChanged
     {
         //在更改属性值时发生。
         event PropertyChangedEventHandler PropertyChanged;
     }
    

    定义很简单,我们可以看到这个接口只定义了一个事件属性——PropertyChanged。所以这个PropertyChanged就是消息的核心了。

    那么学习应用消息的方法就出现了,即,创建一个继承INotifyPropertyChanged接口的类,然后在类内,实现PropertyChanged就可以了。

    消息的应用

    上面介绍消息是用来传递信息的。那么可能会有同学好奇,引用类型的对象不就可以封装传递信息吗?为什么还要用消息呢?

    因为有些数据是存储在非引用类型的对象中的。比如字符串,或数字等。

    为了让字符串、数字等数据的修改也能如引用类型一样,可以传递回给源,就需要使用消息了。

    下面我们来看下消息的基础用法。

    首先,我们使用WPF创建一个项目,然后创建一个页面,起名为WindowNotify,编辑内容如下:

    <Window x:Class="WpfApplication.WindowNotify"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="WindowNotify" Height="120" Width="200">
        <Grid>
            <StackPanel>
                <TextBox Name="txtName" VerticalAlignment="Top" Height="24" ></TextBox>
                <TextBox Name="txtNameNotify" VerticalAlignment="Top"  Height="24" ></TextBox>
                <Button Click="Button_Click" Height="30" Content="查看结果"></Button>
            </StackPanel>
        </Grid>
    </Window>
    

    接下来,编辑Xaml对于的cs文件,内容如下:

    public partial class WindowNotify : Window
    { 
        private string _KName = "Kiba518"; 
        public string KName
        {
            get { return _KName; }
            set { _KName = value; }
        }
        WindowNotifyViewModel vm;
        public WindowNotify()
        {
            InitializeComponent();
            vm = new WindowNotifyViewModel(); 
            Binding bding = new Binding();
            bding.Path = new PropertyPath("KName");
            bding.Mode = BindingMode.TwoWay; 
            bding.Source = vm; 
            txtNameNotify.SetBinding(TextBox.TextProperty, bding);  
            txtName.Text = KName;
            txtNameNotify.Text = vm.KName; 
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            MessageBox.Show("[txtName:" + KName + "]     |    [txtNameNotify:" + vm.KName + "]");
        } 
    }
    public class WindowNotifyViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        private string _KName = "Kiba518Notify";
        public string KName
        {
            get { return _KName; }
            set
            {
                _KName = value;
                if (this.PropertyChanged != null)
                {
                    this.PropertyChanged(this, new PropertyChangedEventArgs("KName"));
                }
            }
        }
    }
    

    这里我们创建了一个ViewModel——WindowNotifyViewModel,我们让这个VM继承INotifyPropertyChanged,然后定义了一个KName属性,并定义了PropertyChanged事件触发的位置。

    有同学可能会好奇,PropertyChanged事件是何时被赋值的呢?别心急,请耐心往下看。

    ViewModel定义完成之后,我们再看Xaml对应的cs文件。这里我们也定义了一个KName属性。然后初始化时,将cs文件的KName和VM的KName分别赋值给前台定义的两个TextBox控件。

    这里用vm的KName属性赋值时,稍微有点特别,稍后再介绍。

    然后我们运行页面,并修改两个文本框内的值。再点击查看结果按钮。得到界面如下:

    可以从图中看到,界面修改了TextBox的Text属性,WindowNotifyViewModel的KName属性对修改的值进行了同步,而WindowNotify的KName没有同步。

    看完结果,我们回过来看下VM的KName的奇怪赋值方式。我们先看第一句:

    Binding bding = new Binding();

    这里的Binding是绑定的意思,这行代码很明显是用来定义一个绑定。

    绑定是个不好理解的词,我们该如何理解呢?

    很简单,我们可以将绑定理解为套索,既然是套索,那么就该有两个属性,一个是套头,一个是套尾。

    那么声明了套索之后,我们便需要为套索的索尾赋值了,即数据源的这一方。 

    代码里,我们通过Binding的Path和Source设置了索尾的数据源和数据源绑定的属性。之后我们还设置了绑定模式是双向绑定,即双方修改都会进行数据传递。

    设置好了套索后,我们在让TextBox控件自己转进套头里,并设置了TextBox控件绑定的属性。代码如下:

    txtNameNotify.SetBinding(TextBox.TextProperty, bding);  

    在我们TextBox控件自己转进套头里的时候,会对数据源的PropertyChanged进行赋值,这样我们就实现了字符串数据的传输。

    当然,这样赋值看起来比较笨拙。那么有更简便的方法吗。

    答案当然是:有。

    MVVM的基础应用

    上面的代码已经实现了ViewModel,那么只要在这个基础上进行优化,即可实现最简单的MVVM的应用。

    优化Xaml代码如下:

    <StackPanel> 
        <TextBox Name="txtNameNotify" Text="{Binding KName}" VerticalAlignment="Top"  Height="24" ></TextBox>
        <Button Click="Button_Click" Height="30" Content="查看结果"></Button>
    </StackPanel>
    

    优化Xaml.cs代码如下: 

     public partial class WindowNotify : Window
     {  
         public WindowNotify()
         {
             InitializeComponent();
             this.DataContext = new WindowNotifyViewModel(); 
          
         }
         private void Button_Click(object sender, RoutedEventArgs e)
         {
             var vm = this.DataContext as WindowNotifyViewModel;
             MessageBox.Show("[txtNameNotify:" + vm.KName + "]");
         } 
     }
     public class WindowNotifyViewModel : INotifyPropertyChanged
     {
         public event PropertyChangedEventHandler PropertyChanged;
         private string _KName = "Kiba518";
         public string KName
         {
             get { return _KName; }
             set
             { 
                 _KName = value;
                 if (this.PropertyChanged != null)
                 {
                     this.PropertyChanged(this, new PropertyChangedEventArgs("KName"));
                 }
             }
         }
     }

    从上面的代码中,我们可以看到在Xaml文件中,Text属性可以使用{Binding KName}这种简写的模式,来实现刚才那个复杂的binding赋值。

    而在Xaml.cs文件中,我们将VeiwMode赋值给了DataContext这个数据上下文,然后,我们就看到了,前台直接使用了VM里的属性。

    这样简单的MVVM就实现了。

    简洁的ViewModel

    在上面我们看到了ViewModel的创建和使用,但ViewMode中每个属性都要设置成如此复杂的形态,稍微有点难受。

    那么,我们来用CallerMemberName继续简化这个ViewModel。

    优化后的代码如下:

    public class WindowNotifyViewModel : BaseViewModel
    { 
        private string _KName = "Kiba518";
        public string KName
        {
            get { return _KName; }
            set
            { 
                _KName = value;
                OnPropertyChanged(); 
            }
        }
    }
    public class BaseViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName]string propertyName = "")
        { 
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        } 
    }
    

    如上所示,我们定义了一个BaseViewModel,并在BaseViewModel里面定义方法OnPropertyChanged,并在里面实现事件PropertyChanged的触发定义。

    最后我们通过CallerMemberName特性,在方法OnPropertyChanged里来获取触发该方法的属性的名称。

    然后我们就实现了,比较简洁的ViewModel。

    PS:CallerMemberName的用法就好像param参数一样,只要如上所示,写进去即可。

    结语

    到此,消息的应用就讲完了。消息毫无疑问是MVVM的技术核心。学会消息才能更好的理解MVVM。

    并且学会消息,还能帮助我们更好的理解现在流行的前端JS的MVVM。虽然实现方式不一样,但道理是一样的。

    C#语法——元组类型

    C#语法——泛型的多种应用

    C#语法——await与async的正确打开方式

    C#语法——委托,架构的血液

    C#语法——事件,逐渐边缘化的大哥。

    我对C#的认知。

    ----------------------------------------------------------------------------------------------------

    注:此文章为原创,任何形式的转载都请联系作者获得授权并注明出处!
    若您觉得这篇文章还不错,请点击下方的推荐】,非常感谢!

     

  • 相关阅读:
    NGINX基本概念
    IP地址进制转换
    路由
    ip ,网段, 网关
    ipaddress模块
    第53课 被遗弃的多重继承(上)
    const static valitate 区别
    第49课 多态的概念和意义 (虚函数virtual)
    第75课 图的遍历(深度优先遍历DFS)
    第74课 图的遍历(广度优先遍历BFS)
  • 原文地址:https://www.cnblogs.com/kiba/p/9453329.html
Copyright © 2020-2023  润新知