2021-05-06

WPF之数据绑定基类

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

数据绑定方法

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









原文转载:http://www.shaoqun.com/a/723767.html

跨境电商:https://www.ikjzd.com/

agora:https://www.ikjzd.com/w/2176

asinseed:https://www.ikjzd.com/w/533


在使用自定义类型作为界面的数据源时,自定义类型需要自己实现INotifyPropertyChanged接口,一般会把INotifyPropertyChanged接口的实现放到一个基类中。数据绑定方法在使用集合类型作为列表控件的ItemsSource时一般会考虑使用ObservalbeCollection,它实现了INotifyCollectionChanged和INotifyPropertyCha
深兰科技:https://www.ikjzd.com/w/1517
cares:https://www.ikjzd.com/w/1302
f2c:https://www.ikjzd.com/w/1242
速卖通如何打造爆款?:https://www.ikjzd.com/home/113859
Facebook加密货币Libra或无缘印度市场?:https://www.ikjzd.com/home/99011
联邦快递起诉美国商务部,被美国司法部驳回!:https://www.ikjzd.com/home/107413

No comments:

Post a Comment