C#语法:消息,MVVM的核心技术

2018 年 8 月 17 日 DotNet

(点击上方蓝字,可快速关注我们)


来源:kiba518

cnblogs.com/kiba/p/9453329.html


在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#语法:await与async的正确打开方式 》 


《C#语法:泛型的多种应用 》


看完本文有收获?请转发分享给更多人

关注「DotNet」,提升.Net技能 

登录查看更多
0

相关内容

【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
还在修改博士论文?这份《博士论文写作技巧》为你指南
【实用书】Python技术手册,第三版767页pdf
专知会员服务
234+阅读 · 2020年5月21日
【新书】Python数据科学食谱(Python Data Science Cookbook)
专知会员服务
114+阅读 · 2020年1月1日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
22+阅读 · 2019年11月7日
用 Python 开发 Excel 宏脚本的神器
私募工场
26+阅读 · 2019年9月8日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
一个牛逼的 Python 调试工具
机器学习算法与Python学习
15+阅读 · 2019年4月30日
C# 10分钟完成百度人脸识别
DotNet
3+阅读 · 2019年2月17日
如何编写完美的 Python 命令行程序?
CSDN
5+阅读 · 2019年1月19日
一天精通无人中级篇:遥控器协议 S-BUS
无人机
51+阅读 · 2018年12月20日
教你实现超流行的骨架屏预加载动态效果
IMWeb前端社区
73+阅读 · 2018年11月27日
Arxiv
24+阅读 · 2020年3月11日
Arxiv
8+阅读 · 2018年2月23日
VIP会员
相关VIP内容
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
192+阅读 · 2020年6月29日
【2020新书】使用高级C# 提升你的编程技能,412页pdf
专知会员服务
57+阅读 · 2020年6月26日
还在修改博士论文?这份《博士论文写作技巧》为你指南
【实用书】Python技术手册,第三版767页pdf
专知会员服务
234+阅读 · 2020年5月21日
【新书】Python数据科学食谱(Python Data Science Cookbook)
专知会员服务
114+阅读 · 2020年1月1日
【电子书】C++ Primer Plus 第6版,附PDF
专知会员服务
87+阅读 · 2019年11月25日
【电子书】Flutter实战305页PDF免费下载
专知会员服务
22+阅读 · 2019年11月7日
相关资讯
用 Python 开发 Excel 宏脚本的神器
私募工场
26+阅读 · 2019年9月8日
用Now轻松部署无服务器Node应用程序
前端之巅
16+阅读 · 2019年6月19日
一个牛逼的 Python 调试工具
机器学习算法与Python学习
15+阅读 · 2019年4月30日
C# 10分钟完成百度人脸识别
DotNet
3+阅读 · 2019年2月17日
如何编写完美的 Python 命令行程序?
CSDN
5+阅读 · 2019年1月19日
一天精通无人中级篇:遥控器协议 S-BUS
无人机
51+阅读 · 2018年12月20日
教你实现超流行的骨架屏预加载动态效果
IMWeb前端社区
73+阅读 · 2018年11月27日
Top
微信扫码咨询专知VIP会员