数据绑定方法

在使用集合类型作为列表控件的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中的实现(二)数据绑定

最新文章

  1. 从客户端(Content=&quot;&lt;EM &gt;&lt;STRONG &gt;&lt;U &gt;这是测试这...&quot;)中检测到有潜在危险的Request.Form 值。
  2. 用servlet和jsp做探索数据库
  3. 浅谈B树
  4. hdwiki 框架简介
  5. 要在一般处理程序中获取其他页面的session值
  6. android手机操作SD的使用方法
  7. samba 问题Windows能看到文件夹但是不能打开
  8. unison实时双向数据同步
  9. LuCI探究(转)
  10. [TroubleShooting]&amp;#39;trn\bak&amp;#39; is incorrectly formed. SQL Server cannot process this media family.
  11. 非名校毕业年薪20W程序员 心得分享
  12. JSP慕课网之Session
  13. Python中使用MongoEngine1
  14. Codeforces Round #422 (Div. 2)E. Liar sa+st表+dp
  15. 1192:放苹果(dp + 搜索)
  16. python网页爬虫开发之一
  17. /src/applicationContext.xml
  18. MySQL &#183; 关系模型的基本术语
  19. webstorm软件使用记录
  20. Pandas使用to_csv保存中文数据用Excel打开是乱码

热门文章

  1. SQL SERVER跨数据库服务,联表进行查询
  2. 一文搞懂 this、apply、call、bind
  3. Java流程控制:用户交互Scanner
  4. 【codeforces - 1307G】Cow and Exercise
  5. mysql中的基础查询 练习
  6. 翻译:《实用的Python编程》06_02_Customizing_iteration
  7. 手把手教你docker安装宝塔面板
  8. 【牛客网】数据库SQL实战(题解)
  9. python3 int() 各数据类型转int
  10. Ubuntu20.04linux内核(5.4.0版本)编译准备与实现过程-编译前准备(1)