WPF 修改屏幕DPI,会触发控件重新加载Unload/Load
修改屏幕dpi,会触发控件的unloaded/loaded
现象/重现案例
这里简单介绍下,修改屏幕dpi,触发unloaded/loaded的神奇案例
1. 我们新建一个窗口,添加一个usercontrol1,然后在usercontrol1中添加usercontrol2
1 <window x:class="wpfunloadedtriggertest.mainwindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:local="clr-namespace:wpfunloadedtriggertest" 7 mc:ignorable="d" 8 title="mainwindow" height="450" width="800"> 9 <local:usercontrol1></local:usercontrol1> 10 </window> 11 ------------------------------我是分隔线----------------------------------- 12 <usercontrol x:class="wpfunloadedtriggertest.usercontrol1" 13 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 14 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 15 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 16 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 17 xmlns:local="clr-namespace:wpfunloadedtriggertest" 18 mc:ignorable="d" 19 d:designheight="450" d:designwidth="800"> 20 <local:usercontrol2></local:usercontrol2> 21 </usercontrol>
2. 显示窗口后,修改dpi比例
3. 设置完后,会触发unloaded/loaded重新加载
unloaded的触发顺序是usercontrol1-->usercontrol2,window并不会触发unloaded事件!
是不是诡异?我们继续。。。
4. window我们添加一个controltemplate模块
1 <window.template> 2 <controltemplate targettype="window"> 3 <border> 4 <adornerdecorator> 5 <contentpresenter /> 6 </adornerdecorator> 7 </border> 8 </controltemplate> 9 </window.template>
再重复2、3步骤,unloaded的触发顺序变了:
触发usercontrol2的unloaded,window、usercontrol1并不会触发unloaded事件!
问题分析
第2步骤中修改dpi后,unloaded事件不一定触发。如何必现呢?
将窗口靠近到任务栏上方,再修改文本比例。
我们查看调用堆栈,貌似是系统给窗口发送消息然后调用broadcastunloadedevent事件,触发unload
所以应该是修改dpi,窗口宽高超出了当前屏幕尺寸范围,系统对usercontrol的视觉树进行重新加载布局。
至于窗口没有触发unloaded、以及在窗口添加以上模块后下一级子控件也没有触发unloaded事件的原因,暂不了解
而对wpf-unloaded/loaded的已知情况如下:
- frameworkelement, 第一次加载显示时,会触发loaded。元素被释放时,会触发unloaded。窗口show/close时,视觉树变化都会触发加载事件
- menuitem, 在frameworkelement基础上,每次和隐藏menuitem时,会额外触发load/unloaded
- tabcontrol,当你选中一个tabitem时会触发loaded,当你取消选中一个tabitem时会触发unloaded,所以切换tab时必定有一个loaded一个unloaded。
- expander,每次被expanded扩展时会引发loaded,但当隐藏时不会引发unloaded。
以上问题的解决方案?暂时没有解决方案,只有规避措施,不要过于依赖于unload/loaded,而且使用了unload/loaded时也要添加注销机制,防止重入
我在github提了个issue:after modified screen dpi,unloaded/loaded is trigged unexpectedly