WPF中Adorner装饰器是否可以捕获RoutedCommand路由命令?
WPF Adorner捕获RoutedCommand解决方案
问题核心原因
- RoutedCommand的路由依赖指定的触发源(
Execute方法的第二个参数),现有代码调用Commands.PlayMovieCommand.Execute(null,null)时传入的源为null,路由只会在当前ChartCanvas范围内查找绑定,不会流向Adorner控件。 - Adorner的视觉树默认挂载在独立的AdornerLayer下,和ChartCanvas的主视觉树平级,没有主动指定源的情况下路由不会主动流向Adorner节点。
可落地解决方案
方案1:指定命令路由源(最推荐,改动最小)
首先在ChartCanvas中存储当前激活的影片Adorner实例,触发命令时指定Adorner内的自定义控件为路由源:
- ChartCanvas类中新增字段存储当前激活的Adorner:
// ChartCanvas类中新增 private UIElementAdorner _activeMovieAdorner;
- 点击ListBoxItem生成Adorner的逻辑中,给上述字段赋值:
// 生成Adorner的代码处补充 _activeMovieAdorner = 新建的UIElementAdorner实例;
- 修改ChartCanvas的PlayMovie方法:
private void PlayMovie() { // 传入Adorner承载的自定义控件作为路由源 Commands.PlayMovieCommand.Execute(null, _activeMovieAdorner?.m_element); }
该方案直接让路由从目标MovieControl开始查找绑定,可直接触发已经写好的OnPlayMovieCommand逻辑。
方案2:Adorner层添加命令中转绑定
如果场景支持同时存在多个影片Adorner,需要批量触发命令,可以在UIElementAdorner的构造函数中添加命令绑定中转:
public UIElementAdorner(UIElement adornedElement, UIElement element) : base(adornedElement) { m_element = element; _adornedElement = adornedElement as Border; if (_adornedElement is null) throw new ArgumentException("This adorner requires a Border element of sizing in MeasureOverride and Arrangement."); // 新增命令中转绑定 CommandBindings.Add(new CommandBinding(Commands.PlayMovieCommand, (sender, e) => { if (m_element is IInputElement target) { Commands.PlayMovieCommand.Execute(e.Parameter, target); } e.Handled = false; })); }
方案3:直接调用(最简场景适用)
如果每次只会存在一个激活的影片Adorner,可直接暴露Adorner内部的MovieControl实例,在PlayMovie中直接调用播放方法,跳过路由命令的复杂逻辑,避免路由问题。
注意事项
- 使用RoutedCommand时必须确保
Execute方法的第二个参数不为null,否则路由无法正常传递。 - Adorner的逻辑树和视觉树独立于被装饰元素的主树,需要主动关联才能参与路由流程。
内容的提问来源于stack exchange,提问作者Alan Wayne
相关产品推荐
相关产品推荐

