需求背景

需要显示 ViewModel 中的 Message/DpMessage,显示内容根据其某些属性来确定。代码结构抽象如下:

// Model
public class Message : INotifyPropertyChanged
{
public string MSG;
public string Stack;
} // ViewModel
public class MessageViewModel : INotifyPropertyChanged
{
public Message { get; set; }
public static readonly DpMessageProperty = DependencyProperty.Register(...)
}
<TextBox Text="{Binding Message, Converter={x:static ShowDetailMessageConverter}}"/>
<TextBox Text="{Binding DpMessage, Converter={x:static ShowDetailMessageConverter}}"/>

以上代码,注意,两个 Text 绑定的目标都是 MessageViewModel,绑定的 Path 分别是 Message、DpMessage。

当 Message 或者 DpMessage 变化(注意,变化指的是重新赋值,即,引用了新的 Message 实例),绑定的目标会收到通知,更新 UI。

问题来了

当 Message 或者 DpMessage 的属性变化了呢,Message 类是实现了 INotifyPropertyChanged 的,属性变化能触发自身的变化(MessageViewModel.INotifyPropertyChanged)通知吗?答案是,不能。即,Message .MSG 者 Message .Stack 变化了,View 不能得到更新通知!这不符合需求。

  • 当然,这个问题可以通过更改绑定对象避过,即,将绑定对象直接设置为 Message 或者 DpMessage,然后使用 MultiBinding,将需要的属性都绑定过去,也可以同样实现需求,但是,这种方式的缺点多:繁琐(如果涉及的属性数量非常大呢)、不直观(目标是 Message 整体,却绑定了其属性)等。

Message 属性(实现 INotifyPropertyChanged)的解决方法

在 Message .PropertyChanged 中监测属性变化,变化时主动调用 MessageViewModel.OnPropertyChanged。这是很简单的。

DpMessage 依赖属性的解决方法

不同于 INotifyPropertyChanged,依赖属性无法通过 OnPropertyChanged 函数触发属性变更通知,这个函数仅作为回调函数使用。因此,查看源码,看看.Net如何去触发的通知,找到函数如下:

/// <summary>
/// This is to enable some performance-motivated shortcuts in property
/// invalidation. When this is called, it means the caller knows the
/// value of the property is pointing to the same object instance as
/// before, but the meaning has changed because something within that
/// object has changed.
/// </summary>
/// <remarks>
/// Clients who are unaware of this will still behave correctly, if not
/// particularly performant, by assuming that we have a new instance.
/// Since invalidation operations are synchronous, we can set a bit
/// to maintain this knowledge through the invalidation operation.
/// This would be problematic in cross-thread operations, but the only
/// time DependencyObject can be used across thread in today's design
/// is when it is a Freezable object that has been Frozen. Frozen
/// means no more changes, which means no more invalidations.
///
/// This is being done as an internal method to enable the performance
/// bug #1114409. This is candidate for a public API but we can't
/// do that kind of work at the moment.
/// </remarks>
[FriendAccessAllowed] // Built into Base, also used by Framework.
internal void InvalidateSubProperty(DependencyProperty dp)
{
// when a sub property changes, send a Changed notification
// with old and new value being the same, and with
// IsASubPropertyChange set to true
NotifyPropertyChange(new DependencyPropertyChangedEventArgs(dp,
dp.GetMetadata(DependencyObjectType), GetValue(dp)));
}

注意函数说明部分:

when a sub property changes, send a Changed notification with old and new value being the same, and with IsASubPropertyChange set to true。

这完全符合我们的需求!!!这个函数本意是作为 Public API 的,但是由于性能的 bug #1114409,将其内部化了。那么,我可以通过反射去调用它:

{
this.InvokeInternal<DependencyObject>("NotifySubPropertyChange", new object[] { DpColorProperty });
} /// <summary>
/// 反射调用指定类型的 Internal 方法。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="caller"></param>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static object InvokeInternal<T>(this T caller, string method, object[] parameters)
{
MethodInfo methodInfo = typeof(T).GetMethod(method, BindingFlags.Instance | BindingFlags.NonPublic);
return methodInfo?.Invoke(caller, parameters);
}

好了,完美解决!

WPF 主动触发依赖属性的 PropertyChanged的更多相关文章

  1. WPF中的依赖属性

    1. WPF中的依赖属性 依赖属性是专门基于WPF创建的.在WPF库实现中,依赖属性使用普通的C#属性进行了包装,使用方法与普通的属性是相同的. 1.1 依赖属性提供的属性功能 资源 数据绑定 样式 ...

  2. WPF 精修篇 依赖属性

    原文:WPF 精修篇 依赖属性 依赖属性使用场景 1. 希望可在样式中设置属性. 2. 希望属性支持数据绑定. 3. 希望可使用动态资源引用设置属性. 4. 希望从元素树中的父元素自动继承属性值. 5 ...

  3. [No000012D]WPF(5/7)依赖属性

    介绍 WPF带来了很多传统 Windows 应用程序没有的新特性和选择.我们已经讨论了一些 WPF 的特性,是时候更进一步介绍其他特性了.当你读完这个系列之前的文章,我希望你已经或多或少地了解了 WP ...

  4. WPF教程:依赖属性

    一.什么是依赖属性 依赖属性就是一种自己可以没有值,并且可以通过绑定从其他数据源获取值.依赖属性可支持WPF中的样式设置.数据绑定.继承.动画及默认值. 将所有的属性都设置为依赖属性并不总是正确的解决 ...

  5. WPF usercontrol 自定义依赖属性

    1.依赖属性不同意一般属性,一般属性主要定义在对象中,而依赖属性是存在一个特殊的依赖属性表中.2.当我们触发改变值时,需要通过SetValue这种方式进行触发. UserControl1.xaml: ...

  6. (原创)2. WPF中的依赖属性之二

    1 依赖属性 1.1 依赖属性最终值的选用 WPF属性系统对依赖属性操作的基本步骤如下: 第一,确定Base Value,对同一个属性的赋值可能发生在很多地方.还用Button的宽度来进行举例,可能在 ...

  7. WPF学习笔记——依赖属性(Dependency Property)

    1.什么是依赖属性 依赖属性是一种可以自己没有值,并且通过Binding从数据源获得值(依赖在别人身上)的属性,拥有依赖属性的对象被称为"依赖对象". 依赖项属性通过调用 Regi ...

  8. 【转】【WPF】关于依赖属性的ValidateValueCallback,PropertyChangedCallback和CoerceValueCallback的执行顺序

    三个回调对应依赖属性的验证过程,改变过程和强制转换过程. class Dobj : DependencyObject { //依赖属性包装 public int MyProperty { get { ...

  9. WPF基础到企业应用系列7——深入剖析依赖属性(WPF/Silverlight核心)

    一. 摘要 首先圣殿骑士非常高兴这个系列能得到大家的关注和支持.这个系列从七月份開始到如今才第七篇,上一篇公布是在8月2日,掐指一算有二十多天没有继续更新了,最主要原因一来是想把它写好,二来是由于近期 ...

随机推荐

  1. pandas数据分析API常用操作

    1.导入数据 df = pd.read_csv( # 该参数为数据在电脑中的路径,可以不填写 filepath_or_buffer='/Users/Weidu/Desktop/sz000002.csv ...

  2. 让 Mongoose 不再重复链接数据库(如何正确连接以解决升级后的报错)

    升级了 Mongoose 后,发现项目打不开了.报错: MongooseError: You can not `mongoose.connect()` multiple times while con ...

  3. ubuntu20.04并添加桌面快捷方式,以安装火狐可浏览器开发版(水狐)为例

    @参考原文 1. 下载linux版源文件 从火狐官网下载linux版的水狐源文件压缩包,@火狐浏览器开发版(水狐)下载地址. 2. 解压下载源文件 将下载的"tar.bz2"文件解 ...

  4. Flink可靠性的基石-checkpoint机制详细解析

    Checkpoint介绍 checkpoint机制是Flink可靠性的基石,可以保证Flink集群在某个算子因为某些原因(如 异常退出)出现故障时,能够将整个应用流图的状态恢复到故障之前的某一状态,保 ...

  5. libuv中实现tcp服务器

    目录 1.说明 2.libuv的tcp server 3.API简介 3.1.uv_tcp_init 3.2.uv_ip4_addr 3.3.uv_tcp_bind 3.4.uv_listen 3.5 ...

  6. 使用Python的pandas模块、mplfinance模块、matplotlib模块绘制K线图

    目录 pandas模块.mplfinance模块和matplotlib模块介绍 pandas模块 mplfinance模块和matplotlib模块 安装mplfinance模块.pandas模块和m ...

  7. SpringMVC听课笔记(SpringMVC 表单标签 & 处理静态资源)

    1.springmvc表单标签,可以快速开发,表单回显,但是感触不深 2.静态资源的获取,主要是要配置这个

  8. Java——介绍

    Java基础语法: 一个Java程序可以认为是一系列对象的集合,而这些对象通过彼此的方法来协同工作. 对象: 对象是类的一个实例,有状态和行为.例如,一条狗是一个对象,它的状态有:颜色.名字.品种:行 ...

  9. scala 时间,时间格式转换

    scala 时间,时间格式转换 1.scala 时间格式转换(String.Long.Date) 1.1时间字符类型转Date类型 1.2Long类型转字符类型 1.3时间字符类型转Long类型 2. ...

  10. java架构《Socket网络编程基础篇》

    本章主要介绍Socket的基本概念,传统的同步阻塞式I/O编程,伪异步IO实现,学习NIO的同步非阻塞编程和NIO2.0(AIO)异步非阻塞编程. 目前为止,Java共支持3种网络编程模型:BIO.N ...