数据绑定方法

在使用集合类型作为列表控件的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. JPress企业站主题-zbout

    JPress企业站主题-zbout 经典的黑白灰颜色搭配风格,首页配置有轮播图.案例展示.公司简介.新闻中心.联系方式以及合作伙伴模块,全站使用了响应式结构,可以自适应电脑端和手机端浏览器访问.主题整 ...

  2. NumPy 将停止支持 Python 2

    NumPy 项目宣布将停止支持 Python 2.Python 核心团队已经决定在 2020 年停止支持 Python 2,而 NumPy 项目自 2010 年以来同时支持 Python 2 和 Py ...

  3. Python3+pygame实现的flappy bird游戏,代码完整,还有音乐

    之前一直在手机上玩flappy bird游戏,闲暇时间就编写了一个 是采用python3+pygame模块制作而成的,运行效果非常流畅,会让你大吃一惊哦哈哈 一.运行效果展示 下载游戏之后,注意在自己 ...

  4. gulp打包详解

    gulp的作用 删除文件中冗余的内容,压缩文件,减小文件体积 实际项目中运行的都是压缩完成以后的文件 减小加载响应时间 gulp打包压缩对象 html,css,js,sass,webserver 音频 ...

  5. C# 获取Word文本高亮和背景(附vb.net代码)

    Word中的文本高亮和背景是通过不同方法来设置的.文本高亮(Text Highlight Color)是通过[字体]中的快速工具栏设置:文本背景(Text Background/Shading)是通过 ...

  6. [go-linq]-Go的.NET LINQ式查询方法

    关于我 我的博客|文章首发 开发者的福音,go也支持linq了 坑爹的集合 go在进行集合操作时,有很不舒服的地方,起初我真的是无力吐槽,又苦于找不到一个好的第三方库,只能每次写着重复代码.举个栗子 ...

  7. java例题_06 最大公约数&最小公倍数

    1 /*6 [程序 6 求最大公约数及最小公倍数] 2 题目:输入两个正整数 m 和 n,求其最大公约数和最小公倍数. 3 程序分析:利用辗除法. 4 */ 5 6 /*分析 7 * ======== ...

  8. .net 预处理指令符的使用

    目录 什么是预处理指令符? 预处理指令符的使用 自定义指令符 使用Visual Studio快速定义指令符 定义指令符区域 什么是预处理指令符? 当C#编译器找到一条预处理指令#if,最后找到一条指令 ...

  9. 滴水逆向初级-C语言(二)

    2.1.C语言的汇编表示 c语言代码 int plus(int x,int y) { return 0; } void main() { __asm { mov eax,eax } //调用函数 pl ...

  10. 通过Dapr实现一个简单的基于.net的微服务电商系统

    本来想在Dpar 1.0GA时发布这篇文章,由于其他事情耽搁了放到现在.时下微服务和云原生技术如何如荼,微软也不甘示弱的和阿里一起适时推出了Dapr(https://dapr.io/),园子里关于da ...