需求背景

需要显示 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. ctfhub技能树—sql注入—Cookie注入

    手注 打开靶机 查看页面信息 查找cookie 测试是否为cookie注入 抓包 尝试注入 成功查询到数据库名 查询表名 查询字段名 查询字段信息 成功拿到flag sqlmap 查询数据库名 pyt ...

  2. [Usaco2009 Feb]Revamping Trails 道路升级

    题目描述 每天,农夫John需要经过一些道路去检查牛棚N里面的牛. 农场上有M(1<=M<=50,000)条双向泥土道路,编号为1..M. 道路i连接牛棚P1_i和P2_i (1 < ...

  3. 制作 Ubuntu 16.04 离线apt源

    1.下载离线安装包 ubuntu下安装包都会下载到/var/cache/apt/archives下,首先清空该目录 sudo apt-get clean 下载需要安装包 sudo apt-get in ...

  4. Redis 核心篇:唯快不破的秘密

    天下武功,无坚不摧,唯快不破! 学习一个技术,通常只接触了零散的技术点,没有在脑海里建立一个完整的知识框架和架构体系,没有系统观.这样会很吃力,而且会出现一看好像自己会,过后就忘记,一脸懵逼. 跟着「 ...

  5. Jmeter-插件扩展及性能监控插件的安装

    需要对http服务进行大数据量的传值测试:看看产品中的http服务,能支持传多少字符:目标值是希望能到10w+: 上次测试中,服务器总是内存满导致服务不响应,因此想增加对服务端的性能监控:查阅了smi ...

  6. Caffeine 缓存库

    介绍 Caffeine是一个基于Java8开发的提供了近乎最佳命中率的高性能的缓存库. 缓存和ConcurrentMap有点相似,但还是有所区别.最根本的区别是ConcurrentMap将会持有所有加 ...

  7. 广告召回 Query-Ad Matching

    小结: 1.最为基础的召回链路就是要保证召回层的相关性,但是相关性高的广告并不一定具有很高的商业价值,所以开始尝试将一些商业化业务指标作为召回的依据 百度凤巢新一代广告召回系统--"莫比乌斯 ...

  8. PB 级大规模 Elasticsearch 集群运维与调优实践

    PB 级大规模 Elasticsearch 集群运维与调优实践 https://mp.weixin.qq.com/s/PDyHT9IuRij20JBgbPTjFA | 导语 腾讯云 Elasticse ...

  9. JAD 反编译

    自动拆装箱 对于基本类型和包装类型之间的转换,通过xxxValue()和valueOf()两个方法完成自动拆装箱,使用jad进行反编译可以看到该过程: public class Demo { publ ...

  10. Spring听课笔记(tg)2

    配置Bean -- 配置形式:基于XML 文件的方式, 基于注解的方式 -- Bean的配置方式:通过全类名(反射).通过工厂方法(静态工厂方法&实例工厂方法).FactoryBean -- ...