数据绑定方法

在使用集合类型作为列表控件的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. rest framework parsers

    解析器 机交互的Web服务更倾向于使用结构化的格式比发送数据格式编码的,因为他们发送比简单的形式更复杂的数据 -马尔科姆Tredinnick,Django开发组 REST框架包含许多内置的解析器类,允 ...

  2. 2018.8.30 nowcoder oi赛制测试1

    2018.8.30 nowcoder oi赛制测试1 普及组难度,发现了一些问题 A 题目大意:求斐波那契数列\(f(k-1)f(k+1)-f(k)^2\),范围极大 打表可得规律 其实是卡西尼恒等式 ...

  3. 基于autofac的属性注入

    基于autofac的属性注入 什么是属性注入 在了解属性注入之前,要先了解一下DI(Dependency Injection),即依赖注入.在ASP.NET Core里自带了一个IOC容器,而且程序支 ...

  4. python-顺序串基本操作的实现

    1 #*********************************************************************** ** 2 #> File Name: seq ...

  5. Git - 使用命令和P4Merge进行diff

    P4Merge P4Merge是Git的一个第三发Diff和Merge工具(可视化冲突解决工具). 下载地址: https://www.perforce.com/downloads/visual-me ...

  6. 20184307 实验三 Socket编程技术

    实验三 Socket编程技术 学号 20184307 2019-2020-2 <Python程序设计>实验三报告 课程:<Python程序设计> 班级:1843 姓名:章森洋 ...

  7. JS定时器使用,定时定点,固定时刻,循环执行

    JS定时器使用,定时定点,固定时刻,循环执行 本文概述:本文主要介绍通过JS实现定时定点执行,在某一个固定时刻执行某个函数的方法.比如说在下一个整点执行,在每一个整点执行,每隔10分钟定时执行的方法. ...

  8. [GDKOI2021] 提高组 Day 1 总结

    [ G D K O I 2021 ]    提 高 组    D a y   1    总 结 [GDKOI2021]~~ 提高组~~ Day~1~~ 总结 [GDKOI2021]  提高组  Day ...

  9. CPU发展史和相关品牌介绍

    CPU发展史和相关品牌介绍 CPU发展已经有40多年的历史了.我们通常将其分成 六个阶段. (1)第一阶段 (1971年-1973年) .这是4位和8位低档微处理器时代,代表产品是Intel 4004 ...

  10. JS基础学习第三天

    条件分支语句switch语句语法: 1234567891011121314 switch(条件表达式){ case 表达式: 语句... break; case 表达式: 语句... break; c ...