数据绑定方法

在使用集合类型作为列表控件的ItemsSource时一般会考虑使用ObservalbeCollection,它实现了INotifyCollectionChangedINotifyPropertyChanged接口,能把集合的变化立刻通知显示它的列表控件,改变会立刻显现出来。

在使用自定义类型作为界面的数据源时,自定义类型需要自己实现INotifyPropertyChanged接口,一般会把INotifyPropertyChanged接口的实现放到一个基类中。

BindableBase基类

下面的BindableBase类来自Prism,代码如下:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices; /// <summary>
/// 实现 <see cref="INotifyPropertyChanged"/>
/// </summary>
public abstract class BindableBase : INotifyPropertyChanged
{
/// <summary>
/// 属性值更改时发生
/// </summary>
public event PropertyChangedEventHandler PropertyChanged; /// <summary>
/// 检查属性是否已与设置值相等,设置属性并仅在必要时通知侦听器。
/// </summary>
/// <typeparam name="T">属性的类型</typeparam>
/// <param name="storage">对同时具有getter和setter的属性的引用</param>
/// <param name="value">属性的所需值</param>
/// <param name="propertyName">用于通知侦听器的属性的名称,此值是可选的,从支持CallerMemberName的编译器调用时可以自动提供。</param>
/// <returns>如果值已更改,则为True;如果现有值与所需值匹配,则为false。</returns>
protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value)) return false; storage = value;
RaisePropertyChanged(propertyName); return true;
} /// <summary>
/// 检查属性是否已与设置值相等,设置属性并仅在必要时通知侦听器。
/// </summary>
/// <typeparam name="T">属性的类型</typeparam>
/// <param name="storage">对同时具有getter和setter的属性的引用</param>
/// <param name="value">属性的所需值</param>
/// <param name="propertyName">用于通知侦听器的属性的名称,此值是可选的,从支持CallerMemberName的编译器调用时可以自动提供。</param>
/// <param name="onChanged">属性值更改后调用的操作。</param>
/// <returns>如果值已更改,则为True;如果现有值与所需值匹配,则为false。</returns>
protected virtual bool SetProperty<T>(ref T storage, T value, Action onChanged, [CallerMemberName] string propertyName = null)
{
if (EqualityComparer<T>.Default.Equals(storage, value)) return false; storage = value;
onChanged?.Invoke();
RaisePropertyChanged(propertyName); return true;
} /// <summary>
/// 引发此对象的PropertyChanged事件。
/// <param name="propertyName">用于通知侦听器的属性的名称,此值是可选的,从支持CallerMemberName的编译器调用时可以自动提供。</param>
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
} /// <summary>
/// 引发此对象的PropertyChanged事件。
/// </summary>
/// <param name="args">PropertyChangedEventArgs参数</param>
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
{
PropertyChanged?.Invoke(this, args);
}
}

上面的代码有两点需要注意:

  • 使用EqualityComparer .Default属性创建通用比较,而不是使用Object.Equals()。Default属性检查类型T是否实现System.IEquatable(Of T)接口,如果是,则返回使用该实现的EqualityComparer(Of T)。否则,它返回一个EqualityComparer(Of T),它使用T提供的Object.Equals和Object.GetHashCode的替代。

  • 使用CallerMemberName特性代替常规的属性名称(也可以使用nameof()运算符关键字来传递属性名称),CallerMemberNameAttribute 类允许获取方法调用方的方法或属性名称,而不必使用字符串文字、 慢速反射代码、复杂的表达式树逻辑或代码编织。

使用BindableBase

实现一个StudentViewModel类(继承BindableBase),代码如下

class StudentViewModel : BindableBase
{
private int _id;
public int Id
{
get { return _id; }
set { SetProperty(ref _id, value); }
} private string _name;
public string Name
{
get { return _name; }
set { SetProperty(ref _name, value,new Action(()=> { Id++; })); }
} private int _age;
public int Age
{
get { return _age; }
set { SetProperty(ref _age, value,nameof(this.Age)); }
}
}

主界面的XAML代码如下:

<StackPanel x:Name="stack" Background="LightBlue">
<StackPanel.DataContext>
<local:StudentViewModel Id="6" Age="29" Name="Tim"/>
</StackPanel.DataContext>
<Grid>
<StackPanel>
<TextBox Text="{Binding Path=Id}" Margin="5"/>
<TextBox Text="{Binding Path=Name}" Margin="5"/>
<TextBox Text="{Binding Path=Age}" Margin="5"/>
<Button Content="Age+" Click="Button_Click"/>
</StackPanel>
</Grid>
</StackPanel>

主界面的后台实现Button_Click,代码如下:

private void Button_Click(object sender, RoutedEventArgs e)
{
((StudentViewModel)this.stack.DataContext).Age ++;
}

运行程序,查看数据绑定的效果:

参考资料

PrismLibrary/Prism/BindableBase.cs

INotifyPropertyChanged,.NET 4.6方式

MVVM模式解析和在WPF中的实现(二)数据绑定

WPF之数据绑定基类的更多相关文章

  1. WPF自学入门(九)WPF自定义窗口基类

    今天简单记录一个知识点:WPF自定义窗口基类,常用winform的人知道,winform的窗体继承是很好用的,写一个基础窗体,直接在后台代码改写继承窗体名.但如果是WPF要继承窗体,我个人感觉没有理解 ...

  2. WPF自定义窗口基类

    WPF自定义窗口基类时,窗口基类只定义.cs文件,xaml文件不定义.继承自定义窗口的类xaml文件的根节点就不再是<Window>,而是自定义窗口类名(若自定义窗口与继承者不在同一个命名 ...

  3. wpf之mvvm基类

    当我们用MVVM设计模式的时候要实现INotifyPropertyChanged,每次都要实现这个接口比较麻烦,所以基类的作用就体现出来了.代码如下:   1 2 3 4 5 6 7 8 9 10 1 ...

  4. 《Programming WPF》翻译 第9章 2.选择一个基类

    原文:<Programming WPF>翻译 第9章 2.选择一个基类 WPF提供了很多类,当创建一个自定义元素时,你可以从这些类中派生.图9-1显示了一组可能作为类--可能是合适的基类, ...

  5. WPF组件开发之组件的基类

    之前在网上看到很多关于组件开发的资料,但真正可以用到框架内的却很少.今天贴出自己做的组件,并适合大部分框架的代码. 组件开发需要先做出组件的基类,然后由其他的各类组件去继承这个基类,下面是组件基类的代 ...

  6. WPF 窗体基类实现的体验及实现回车到下一控件

    原文:WPF 窗体基类实现的体验及实现回车到下一控件 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/jsyhello/article/details ...

  7. WPF MVVM 写一个健壮的INotifyPropertyChanged基类

    当我们用MVVM的时候要实现INotifyPropertyChanged,如果你是基于.net4.5以下的framework(.net4.5已有新特性我这里就不说了) 你很可能会这么写 public ...

  8. WPF开发时光之痕日记本(二)—— MVVM基类

    当我们用MVVM的时候要实现INotifyPropertyChanged,每次都要实现这个接口比较麻烦,所以基类的作用就体现出来了.代码如下: public class ViewModelBase : ...

  9. WPF 之 创建继承自Window 基类的自定义窗口基类

    开发项目时,按照美工的设计其外边框(包括最大化,最小化,关闭等按钮)自然不同于 Window 自身的,但窗口的外边框及窗口移动.最小化等标题栏操作基本都是一样的.所以通过查看资料,可按如下方法创建继承 ...

随机推荐

  1. cve-2019-2725 反序列化远程代码执行

    描述:部分版本WebLogic中默认包含的wls9_async_response包,为WebLogic Server提供异步通讯服务.由于该WAR包在反序列化处理输入信息时存在缺陷,攻击者可以发送精心 ...

  2. Hi3559AV100 NNIE开发(3)RuyiStudio软件 .wk文件生成过程-mobilefacenet.cfg的参数配置

    之后随笔将更多笔墨着重于NNIE开发系列,下文是关于Hi3559AV100 NNIE开发(3)RuyiStudio软件 .wk文件生成过程-mobilefacenet.cfg的参数配置,目前项目需要对 ...

  3. 从零学脚手架(四)---babel

    如果此篇对您有所帮助,在此求一个star.项目地址: OrcasTeam/my-cli 接下来介绍一个打包编译过程中一个极为重要的工具--babel. ES6的枷锁 细心的朋友可以知道,在之前打包编译 ...

  4. TensorFlow2.0使用方法

    TensorFlow2.0 1 使用技巧 更新到最新版本: pip install --upgrade tensorflow pip install --upgrade tensorflow-gpu ...

  5. Python3中变量作用域nonlocal的总结

    最近,在工作中踩到了一个关于Python3中nonlocal语句指定的变量作用域的坑.今天趁周六休息总结记录一下. 众所周知,Python中最常见的作用域定义如下:   但是,为了更加方便地在闭包函数 ...

  6. MD摘要算法

    import static org.junit.Assert.*; import java.security.MessageDigest; //消息摘要 public class MDCoder { ...

  7. 学习Python的书籍——入门到进阶

    入门读物 <Python基础教程>(Beginning Python From Novice to Professional) <Python学习手册>(Learning Py ...

  8. ch1_5_1统计最大最小元素的平均比较次数

    public class ch1_5_1统计最大最小元素的平均比较次数 { public static void main(String[] args) { // TODO Auto-generate ...

  9. python学习9 函数的基础知识

    1.函数的定义 def  func(): 2.函数的调用 func() 3.函数的返回值 #1.没有返回值 # (1)不写return # (2)只写return后面的代码不在继续执行,返回空,代表结 ...

  10. Python3实现短信轰炸机

    短信轰炸机的基本原理:利用某些限制不严格的网站短信注册接口,用Python模拟请求,传入被炸人手机号码,实现轰炸 实现方式:利用requests模块.time模块.完成请求模拟 模块安装: 在终端窗口 ...