

如何在保留原本所有样式/绑定和用户设置值的情况下,设置和还原 WPF 依赖项属性的值
source link: https://blog.walterlv.com/post/change-and-restore-wpf-dependency-value-without-disabling-the-declared-use-of-the-property.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

如何在保留原本所有样式/绑定和用户设置值的情况下,设置和还原 WPF 依赖项属性的值
2020-06-02 23:13
WPF 备份某控件的一些属性,做一些神奇的操作,然后再还原这些属性。多么司空见惯的操作呀!然而怎么备份却是值得研究的问题。直接赋值?那一定是因为你没踩到一些坑。
场景和问题
现在,我们假想一个场景(为了编代码方便):
- 有一个窗口,设置了一些样式属性
- 现在需要将这个窗口设置为全屏,这要求修改一些原来的属性(WPF 自带那设置有 bug,我会另写一篇博客说明)
- 取消设置窗口全屏后,之前修改的那些属性要“完美”还原
一般可能会这么写:
private Window _window;
private WindowStyle _oldStyle;
private void OnEnterFullScreen()
{
_oldStyle = _window.WindowStyle;
_window.WindowStyle = WindowStyle.None;
}
private void OnExitFullScreen()
{
_window.WindowStyle = _oldStyle;
}
- 如果某人在
WindowStyle
上设了个动态的样式怎么办?——那当然是不再动态了呀(因为覆盖了样式值) - 如果某人在
WindowStyle
上设置了绑定怎么办?——那当然也是不再生效了呀(因为绑定被你覆盖了)
解决方法和原理
因为各大 WPF 入门书籍都说到了 WPF 依赖项属性的优先级机制,所以大家应该基本都知道这个。不了解的,可以立刻去这里看看:[依赖项属性值优先级 - WPF Microsoft Docs](https://docs.microsoft.com/zh-cn/dotnet/framework/wpf/advanced/dependency-property-value-precedence#dependency-property-setting-precedence-list)。
是这样的优先级:强制 > 动画 > 本地值 > 模板 > 隐式样式 > 样式触发器 > 模板触发器 > 样式 > 默认样式 > 属性继承 > 元数据默认值。
而我们通过在 XAML 或 C# 代码中直接赋值,设置的是“本地值”。因此,如果设置了本地值,那么更低优先级的样式当然就全部失效了。
那么绑定呢?绑定在依赖项属性优先级中并不存在。绑定实际上是通过“本地值”来实现的,将一个绑定表达式设置到“本地值”中,然后在需要值的时候,会 ProvideValue
提供值。所以,如果再设置了本地值,那么绑定的设置就被覆盖掉了。
但是,SetCurrentValue
就是干这件事的!
SetCurrentValue
设计为在不改变依赖项属性任何已有值的情况下,设置属性当前的值。
_window.SetCurrentValue(Window.WindowStyleProperty, WindowStyle.None);
那么,只需要还原 SetCurrentValue
所做的修改,就还原了此依赖项属性的一切设置的值:
_window.InvalidateProperty(Window.WindowStyleProperty);
注意不是 ClearValue
,那会清除本地值。
然而还差一点,绑定如果在你应用 SetCurrentValue
期间有改变,那么这次的赋值并不会让绑定立即生效,所以我们还需要手工再让绑定重新更新值:
BindingOperations.GetBindingExpression(_window, Window.WindowStyleProperty)?.UpdateTarget();
那么,综合起来,本文一开始的代码将更新成如下形式:
private Window _window;
private void OnEnterFullScreen()
{
_window.SetCurrentValue(Window.WindowStyleProperty, WindowStyle.None);
}
private void OnExitFullScreen()
{
_window.InvalidateProperty(Window.WindowStyleProperty);
BindingOperations.GetBindingExpression(_window, Window.WindowStyleProperty)?.UpdateTarget();
}
将代码变得通用一点:
static void ApplyTempProperty(DependencyObject d, DependencyProperty dp, object tempValue)
{
d?.SetCurrentValue(dp, tempValue);
}
static void RestoreProperty(DependencyObject d, DependencyProperty dp)
{
d.InvalidateProperty(dp);
BindingOperations.GetBindingExpression(d, dp)?.UpdateTarget();
}
本文会经常更新,请阅读原文: https://blog.walterlv.com/post/change-and-restore-wpf-dependency-value-without-disabling-the-declared-use-of-the-property.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。
如果你想持续阅读我的最新博客,请点击 RSS 订阅,或者前往 CSDN 关注我的主页。
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected]) 。
Recommend
-
62
上次小编带大家了解了软件测试岗位的第一个特点---就业竞争小,今天咱们继续了解软件测试工程师的第二个特点:薪资待遇好 由于测试人才的短缺,软件测试人员的薪水自然就高,但是大家有没有发现,待遇好跟薪资高,完全是...
-
72
信息安全 - @lzhw - 从其他论坛看到的,通过下面的 api 可以查询 QQ 绑定的手机号信息,包含最新泄露的数据,加上老数据据说总共有 8 亿:http://api.w-seo.cn/qb.php?qq=链
-
6
保留所有数据的数据湖,将为明天创造更多的可能 - 七牛云本文翻译自:dataversity 作者:Amber Lee Dennis 数据湖是一个同时可以存储非结构化数据和结构化数据的池子,以原始格式存储,没有特定目的。白皮书《数据湖是什么和为什么它会流行?》中...
-
17
V2EX › Google GV 已绑定真实手机号且获取了 GV 号码的情况下,能否删掉重新选号而不需要再次验证手机?
-
7
新《使命召唤: 战区》不保留原本《战区》进度,玩家需从头开始
-
6
在Ubuntu系统的嵌入式设备开发过程中,保留文件系统或者说备份当前开发板镜像的需求在不断...
-
4
背景 在公司的日常业务中,存在不少数据的收集提取需求,大部分公司会采取Excel来完成数据的收集和汇总,但这项工作会让负责信息收集的业务人员相当头大。虽然提前做好了数据收集模板,但最终提交上来的模板会被修改的五花八门...
-
7
V2EX › 问与答 抖音是怎么做到在我没有绑定手机号的情况下获得我副卡完整手机号的??
-
10
V2EX › Android 喜马拉雅 APP 怎么做到在关闭所有通知权限的情况下还能做到推送消息的?
-
5
V2EX › Apple 如何在切换 app store 用户时保留下载的音乐
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK