需求背景

需要显示 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. (十二)random模块

    大致有以下几个函数: print(random.random()) #0到1的浮点型 print(random.randint(1,6)) #1到6的整型 print(random.randrange ...

  2. 【MySQL】使用WHERE子句 - 过滤数据

    第6章 过滤数据 文章目录 第6章 过滤数据 1.使用WHERE子句 2.WHERE子句操作符 2.1.检查单个值 2.2.不匹配检查 2.3.范围值检查 2.4.空值检查 3.小结 简单记录 - M ...

  3. DOCKER 安装步骤-最靠谱的笔记

    一.系统环境规划 服务器名 项目名称 docker 操作系统 CentOS Linux release 7.1.1503 (Core) Docker 版本 17.03.2-ce   二.Docker ...

  4. 【MYSQL】DDL语句

    介绍:DDL语句,即数据定义语句,定义了不同的数据段,数据库表.表.列.索引等数据库对象:例如,create.drop.alter 适用对象:一般是由数据库管理员DBA使用 1.连接数据库 mysql ...

  5. 控制tomcat日志文件的输出到catalina.out

    在catalina.sh中直接把下面的内容注释掉即可:

  6. status 404 reading EduClient#getCourseInfoOrder(String)解决过程

    UcenterClient#getUserInfoOrder(String) failed and no fallback available.解决过程 报错内容: com.netflix.hystr ...

  7. Markdown 编辑器+同步预览+文件笔记管理+静态博客 metadata 管理

    Leanote: 1. 笔记管理, 支持富文本, markdown, 写作模式.... 编辑器绝对好用. 另外特意为coder制作了一个贴代码的插件, 真是太贴心(因为作者也是coder) 2. 博客 ...

  8. 陈思淼:阿里6个月重写Lazada,再造“淘宝”的技术总结

    小结: 1. 所谓的中台技术,就是从 IDC,网络,机房,操作系统,中间件,数据库,算法平台,数据平台,计算平台,到业务平台,每一层都有清晰的定义和技术产品. 具体来看,首先,集团技术的分层和每层的产 ...

  9. trust an HTTPS connection 安全协议 随机数 运输层安全协议 应用层安全协议 安全证书

    小结: 1.HTTPS存在不同于HTTP的默认端口及一个加密/身份验证层(在HTTP与TCP之间) HTTPS(全称:Hyper Text Transfer Protocol over Secure ...

  10. git database 数据库 平面文件 Git 同其他系统的重要区别 Git 只关心文件数据的整体是否发生变化,而大多数其他系统则只关心文件内容的具体差异 Git 的设计哲学

    小结: 1.如果要浏览项目的历史更新摘要,Git 不用跑到外面的服务器上去取数据回来 2.注意 git clone  应指定版本,它复制的这个版本的全部历史信息: 各个分支  git init 数据库 ...