WPF继续响应被标记为已处理事件的方法
wpf继续响应被标记为已处理事件的方法
wpf中在冒泡事件或者隧道事件会随其层间关系在visual tree上层层传递,但是,某些事件传递到某些控件是即会”终止“(不再响应相应的注册事件),给人一种事件终结者的印象。例如:textbox对mousdown事件。
产生原因:事件处理到达该控件后,其事件对象属性handled被标记为true。wpf事件引擎在处理控件对应事件时,若检测到该属性为true,就不会调用相应的处理程序。即 wpf路由事件被标记为handled以后, 并不是不在visual tree上传递了;而是,事件引擎不再去调用这个事件的handler了。
若仍想再其上层元素中(上层是相对事件的传递方向而言)仍然处理响应的事件,解决方式:
1、若上层控件可以注册相应事件。即没有重写对应控件的template属性。直接上代码:
<grid mousedown="grid_mousedown" > <textbox name="txt1" text="{binding path=txt1 ,mode=twoway,updatesourcetrigger=propertychanged}" mousedown="txt_mousedown" /> </grid>
1 private void txt_mousedown(object sender, mouseeventargs e) 2 { 3 messagebox.show("textmousedown事件"); 4 e.handled = false;//使冒泡继续上传 5 } 6 7 private void grid_mousedown(object sender, mouseeventargs e) 8 { 9 messagebox.show("gridmousedown事件"); 10 }
2、当自定义控件模板时,绑定模版事件不起效,此时用上面的方法不再生效。例如:自定义列表控件模版样式
<usercontrol x:class="test" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:ignorable="d" d:designheight="290" d:designwidth="180"> <grid name="gridmain"> <itemscontrol focusable="false" background="transparent" itemssource="{binding infomodel, mode=oneway}"> <itemscontrol.template> <controltemplate targettype="itemscontrol"> <border x:name="scrborder"> <scrollviewer x:name="scrollviewer" verticalscrollbarvisibility="auto" horizontalscrollbarvisibility="auto" padding="{templatebinding padding}" mouseleftbuttondown="mouseleftbuttondown"> <itemspresenter /> </scrollviewer> </border> </controltemplate> </itemscontrol.template> <itemscontrol.itemtemplate> <datatemplate> <grid> <grid.columndefinitions> <columndefinition width="*"/> <columndefinition width="auto"/> <columndefinition width="auto"/> </grid.columndefinitions> <textblock text="{binding desc}" grid.column="0"/> <textblock text="{binding value}" margin="0" grid.column="1"/> <textblock text="{binding unit}" grid.column="2" margin="3,0,15,0"/> </grid> </datatemplate> </itemscontrol.itemtemplate> <itemscontrol.itemspanel> <itemspaneltemplate> <stackpanel></stackpanel> </itemspaneltemplate> </itemscontrol.itemspanel> <itemscontrol.itemcontainerstyle> <style> <setter property="control.margin" value="1"/> </style> </itemscontrol.itemcontainerstyle> </itemscontrol> </grid> </usercontrol>
scrollviewer在控件模版中,scrollviewer的mousebuttondown事件处理事件如下:断点设置会发现鼠标点击时并不会触发。
1 private void mouseleftbuttondown(object sender, mousebuttoneventargs e) 2 { 3 //e.handled = false ; 4 }
解决办法:uielement.addhandler 方法:为指定的路由事件添加路由事件处理程序,并将该处理程序添加到当前元素的处理程序集合中。具体解释详见:https://docs.microsoft.com/zh-cn/dotnet/api/system.windows.uielement.addhandler?f1url=https%3a%2f%2fmsdn.microsoft.com%2fquery%2fdev15.query%3fappid%3ddev15idef1%26l%3dzh-cn%26k%3dk(system.windows.uielement.addhandler);k(targetframeworkmoniker-.netframework,version%3dv4.5);k(devlang-csharp)%26rd%3dtrue&view=netframework-4.8
大体意思:由于wpf事件visual tree上传递过程中,某个元素将该事件标记为已处理,导致事件在传递时不再继续有响应,(原因:handled被标记为true)如果希望后续元素也能响应此方法,可以使用此方法。
因此我们可以在上面usercontrol的构造函数中添加下面代码:表示gridmain处理相应鼠标点击事件
1 public usercontrol() 2 { 3 initializecomponent(); 4 5 gridmain.addhandler(mouseleftbuttondownevent, new mousebuttoneventhandler(mouseleftbuttondown), true); 6 }
再次断点调试mouseleftbuttondown,会发现断点命中。
addhandler这个代码的关键点是最后那个true,它告诉wpf引擎相应元素call这个handle,即使它被标记为handled=true。但是元素处理后其上层元素也照样不会相应,因为handle仍被标记已处理。由此可见,wpf路由事件被标记为handled以后,并不是不在visual tree上传递了;而是,不去call这个handler了。
上例中如果想要usercontrol继续响应,处境就与1一样了,只需将handle标记为false即可。
引用博文:
https://www.cnblogs.com/debuglzq/archive/2013/05/07/3062733.html
上一篇: my97日期控件弹出位置显示异常
下一篇: C++函数指针与指针函数干货