赞
踩
在Windows Presentation Foundation(WPF)中,INotifyPropertyChanged是一个核心接口,用于实现类与视图之间的数据双向绑定。当实体类的某个属性值发生变化时,通过实现此接口可以立即通知绑定到属性的所有UI控件进行更新,ICommand主要针对的是关联到任何实现了ICommand接口的对象的方法。
在C#中,CallerMemberName是.NET框架提供的一个编译器特性(Compiler Feature),它允许你获取调用当前方法的成员名称,而无需硬编码该名称。这对于实现INotifyPropertyChanged接口特别有用,因为它可以减少手动输入属性名的工作量,提高代码的健壮性和可维护性。
不管是ICommand还是INotifyPropertyChanged都必须首先将ViewMode的实现设置为控件或整个界面的DataContext。如:
this.DataContext = new MainViewModel();
DataContext是UI层与数据逻辑层的桥梁
DataContext是一个非常关键的概念,它是实现数据绑定的基础。DataContext是所有WPF控件都具有的一个依赖属性。它属于System.Windows.FrameworkElement类。这意味着所有继承自该类的控件都可以使用DataContext。
DataContext作为一个容器,提供了UI层和数据层之间的连接点。在MVVM(Model-View-ViewModel)架构模式中,通常将ViewModel设置为控件或整个界面的DataContext,这样UI控件可以通过绑定直接访问ViewModel中的数据和命令。
<Window>
<Window.DataContext>
<local:MyViewModel/>
</Window.DataContext>
<StackPanel>
<TextBox Text="{Binding Name}" />
<Button Command="{Binding SaveCommand}" Content="Save" />
</StackPanel>
</Window>
上面的示例,Window的DataContext被设置为了MyViewModel实例,因为TextBox和Button都可以通过数据绑定访问到MyViewModel中的Name属性和SaveCommand命令。
public class Person:INotifyPropertyChanged { private string m_Name="默认值是XXXX"; public string Name { get =>m_Name; set { if (m_Name == value) return; m_Name = value; this.Notify("Name"); } } public event PropertyChangedEventHandler PropertyChanged; public void Notify(string propertyName) { PropertyChangedEventHandler handler = this.PropertyChanged; if(handler!=null) handler(this, new PropertyChangedEventArgs(propertyName)); } }
<Window x:Class="WpfToolkitApp.WinMvvmFirst"
...
xmlns:vm="clr-namespace:WpfToolkitApp.Model">
<Window.DataContext>
<vm:Person></vm:Person>
</Window.DataContext>
<Grid>
<Label Content="名称" HorizontalAlignment="Left" Margin="21,104,0,0" VerticalAlignment="Top"/>
<TextBox HorizontalAlignment="Left" Margin="60,104,0,0" TextWrapping="Wrap"
Text="{Binding Name}"
VerticalAlignment="Top"
Width="221"
Height="25"/>
</Grid>
</Window>
public partial class WinMvvmFirst : Window
{
Person person = null;
public WinMvvmFirst()
{
InitializeComponent();
person = base.DataContext as Person;
}
}
public static class NotificationExtensions { public static void Notify(this PropertyChangedEventHandler eventHandler, Expression<Func<object>> expression) { if (eventHandler == null) { return; } var lambda = expression as LambdaExpression; MemberExpression memberExpression; if (lambda.Body is UnaryExpression) { var unaryExpression = lambda.Body as UnaryExpression; memberExpression = unaryExpression.Operand as MemberExpression; } else { memberExpression = lambda.Body as MemberExpression; } var constantExpression = memberExpression.Expression as ConstantExpression; var propertyInfo = memberExpression.Member as PropertyInfo; foreach (var del in eventHandler.GetInvocationList()) { del.DynamicInvoke(new object[] { constantExpression.Value, new PropertyChangedEventArgs(propertyInfo.Name) }); } } }
静态扩展方法使用:
public class Employee : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private string _trueName;
public string TrueName
{
get{return this._trueName}
set
{
this._trueName = value;
this.PropertyChanged.Notify(()=>this.TrueName);
}
}
}
还可以添加一个很实用的扩展:
public static void SubscribeToChange<T>(this T objectThatNotifies, Expression<Func<object>> expression, PropertyChangedEventHandler<T> handler) where T :INotifyPropertyChanged { objectThatNotifies.PropertyChanged +=(s, e) => { var lambda = expression as LambdaExpression; MemberExpression memberExpression; if (lambda.Body is UnaryExpression) { var unaryExpression = lambda.Body as UnaryExpression; memberExpression = unaryExpression.Operand as MemberExpression; } else { memberExpression = lambda.Body as MemberExpression; } var propertyInfo = memberExpression.Member as PropertyInfo; if (e.PropertyName.Equals(propertyInfo.Name)) { handler(objectThatNotifies); } }; }
private string m_myProperty;
public string MyProperty
{
get{return m_myProperty;}
set{
m_myProperty = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = "none passed")
{
}
属性CallerMemberName的解决办法和方法二是基本相同的,不同的这个在net框架中解决的。更多信息可以查看CallerMemberName,Net4.5还提供了CallerFilePath、CallerLineNumber,稍微会详细讲解。
INotifyPropertyChanged
接口用于向客户端发出某一属性值已更改的通知。在应用有两种方式OneTime
模式、OneWay
模式和TwoWay
模式。
OneTime
模式是一个初始化一次绑定。不常用。
绑定源的每一次变化都会通知绑定目标,但是绑定目标的改变不会改变绑定源。当绑定源的数据实体类没有实现INotifyPropertyChanged接口时,当改变了数据源,发现绑定目录的UI上的相应的数据不会立即变化。
TwoWay
模式下,当绑定源的数据实体类没有实现INotifyPropertyChanged接口时,空间的更改会让数据源立即发改变,但是改变数据源,绑定目标控件却不会立即发送改变,所以当我们需要数据源改变时相对应的UI立即改变时,需要实现INotifyPropertyChanged接口。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。