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#语法——消息,MVVM的核心技术。的更多相关文章
- [编织消息框架][JAVA核心技术]动态代理应用4
基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...
- [编织消息框架][JAVA核心技术]异常基础
Java异常体系结构 Thorwable类所有异常和错误的超类,有两个子类Error和Exception,分别表示错误和异常. 其中异常类Exception又分为运行时异常(RuntimeExcept ...
- [编织消息框架][JAVA核心技术]动态代理介绍
由于java是种强类型静态语言,在执行时无法动态生成代码,静态语言基本都有这特性 动态生成代码有几种好处,也是弱类型语言的优点 1.部份逻辑可以实现热更新 2.远程调用实现非常适合 3.能动态生成扩展 ...
- [编织消息框架][JAVA核心技术]动态代理应用4-annotationProcessor
基础部份: 接下来讲编译JAVA时,生成自定义class 我们用 javax.annotation.processing.AbstractProcessor 来处理 public abstract c ...
- [编织消息框架][JAVA核心技术]jdk动态代理
需要用到的工具 jdk : javac javap class 反编译 :JD-GUI http://jd.benow.ca/ import java.lang.reflect.Invocation ...
- [编织消息框架][JAVA核心技术]动态代理应用2
接下来如何实现 第一步:先把服务类,调用方法转换成数字,方便传输 第二步:提取元信息,提取又有三种方式,三种各有优点,最优方式是第一种 1.编译java时处理 2.程序启动时处理,预处理 3.调用时处 ...
- [编织消息框架][JAVA核心技术]动态代理应用5-javassist
基础部份: 修改class我们用到javassist,在pom.xml添加 <properties> <javassist.version>3.18.2-GA</java ...
- [编织消息框架][JAVA核心技术]动态代理应用8-IRpcReceive实现
private static Map<Short, Map<Byte, Method>> RECEIVE_METHOD_INFO = new HashMap<>() ...
- [编织消息框架][JAVA核心技术]动态代理应用9-扫描class
之前介绍的annotationProcessor能在编译时生成自定义class,但有个缺点,只能每次添加/删除java文件才会执行,那天换了个人不清楚就坑大了 还记得之前介绍的编译时处理,懒处理,还有 ...
随机推荐
- bzoj2120 数颜色 分块
分块大法好 orz 处理出每个点的前驱和后继位置. 暴力修改,查询就在每个整块里查询pre<l的,暴力跑两边就好了 #include<cstdio> #include<cstr ...
- BZOJ_1040_[ZJOI2008]骑士_树形DP
BZOJ_1040_[ZJOI2008]骑士_树形DP 题意: Z国的骑士团是一个很有势力的组织,帮会中汇聚了来自各地的精英.他们劫富济贫,惩恶扬善,受到社会各 界的赞扬.最近发生了一件可怕的事情,邪 ...
- BZOJ_1798_[AHOI2009]维护序列_线段树
BZOJ_1798_[AHOI2009]维护序列_线段树 题意:老师交给小可可一个维护数列的任务,现在小可可希望你来帮他完成. 有长为N的数列,不妨设为a1,a2,…,aN .有如下三种操作形式: ( ...
- 关于socket.io的使用
这段时间学习了socket.io,用它写了小项目,在此总结下它的基本使用方式和一些要点. socket.io是基于Node.js和WebSocket协议的实时通信开源框架,它包括客户端的JavaScr ...
- SpringBoot进阶教程(三十)整合Redis之Sentinel哨兵模式
Redis-Sentinel是官方推荐的高可用解决方案,当redis在做master-slave的高可用方案时,假如master宕机了,redis本身(以及其很多客户端)都没有实现自动进行主备切换,而 ...
- 基于Unity的AR开发初探:第一个AR应用程序
记得2014年曾经写过一个Unity3D的游戏开发初探系列,收获了很多好评和鼓励,不过自那之后再也没有用过Unity,因为没有相关的需求让我能用到.目前公司有一个App开发的需求,想要融合一下AR到A ...
- python——绘制二元高斯分布的三维图像,
在对数据进行可视化的过程中,可能经常需要对数据进行三维绘图,在python中进行三维绘图其实是比较简单的,下面我们将给出一个二元高斯分布的三维图像案例,并且给出相关函数的参数. 通常,我们绘制三维图像 ...
- 「拥抱开源, 又见 .NET」系列第三次线下活动简报
「拥抱开源, 又见 .NET」 随着 .NET Core的发布和开源,.NET又重新回到人们的视野. 自2016年 .NET Core 1.0 发布以来,其强大的生命力让越来越多技术爱好者对她的未来满 ...
- .net mvc + layui做图片上传(一)
图片上传和展示是互联网应用中比较常见的一个功能,最近做的一个门户网站项目就有多个需要上传图片的功能模块.关于这部分内容,本来功能不复杂,但后面做起来却还是出现了一些波折.因为缺乏经验,对几种图片上传的 ...
- 用系统为centos6的主机,搭建PXE服务器,实现批量安装centos6,7系统
1. iptables -F setenforce 0 临时关掉selinux,清掉防火墙 永久生效更改配置文件:vim /etc/sysconfig/selinux chkconfig iptabl ...