冒泡路由命令从用户控制到主要 window
Bubbling Routed Commands up from users control to main window
我有一个 RoutedCommand 定义如下:
public static class Commands
{
/// <summary>
/// Represents the Foo feature of the program.
/// </summary>
public static readonly RoutedCommand Foo = new RoutedCommand("Foo", typeof(Window1));
}
然后我有一个用户控件,其命令定义如下:
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.Foo}" Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
<UserControl.InputBindings>
<KeyBinding Command="{x:Static local:Commands.Foo}" Modifiers="Control" Key="Space"></KeyBinding>
</UserControl.InputBindings>
并像这样用代码处理! (针对我的用户控件 class)
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Executed from sub");
}
我的自定义用户控件定义在我的主window:
<local:UserControl1 x:Name="myC" Grid.Row="1" DataContext="{Binding ChildName}"></local:UserControl1>
我的主要 window 也有自己处理 Foo 路由命令的方式:
CommandBindings.Add(new CommandBinding(Commands.Foo, new ExecutedRoutedEventHandler((x, y) => {
MessageBox.Show("Something Happend from main window");
})));
InputBindings.Add(new InputBinding(Commands.Foo, new KeyGesture(Key.P, ModifierKeys.Alt)));
现在,如果命令是从我的用户控件触发的,我希望事件冒泡到 window 如果 ExecutedRoutedEventArgs 的 Handled 属性 设置为 false,并且它是:
但只有来自用户控件的消息框会显示,我希望 window 上已处理事件的消息框会在之后显示!
谢谢
CommandBinding.Executed
事件的处理程序由 CommandBinding.OnExecuted
方法调用,该方法在处理程序完成后立即将 RoutedEventArgs.Handled
设置为 true
。该方法是内部方法而不是虚拟方法,因此您对此行为无能为力。
如果你真的想让父级处理命令,你可以从你的处理程序中调用它。这不是同一个命令,但会导致主程序 window 上的处理程序触发。
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Executed from sub");
var rc = e.Command as RoutedCommand;
var parentInput = FindParentInput();
if (parentInput != null && rc != null)
{
rc.Execute(null, parentInput);
}
}
private IInputElement FindParentInput()
{
DependencyObject element = this;
while (element != null)
{
DependencyObject parent = VisualTreeHelper.GetParent(element);
var input = parent as IInputElement;
if (input != null)
return input;
element = parent;
}
return null;
}
请注意,如果您尝试使用 null
作为第二个参数,它将再次向 this
相同的 UserControl 发送新命令。这就是为什么我包含了 FindParentInput
方法,该方法查找实现了“IInputElement”接口的最近的父级。
你可以做得更简单,似乎所有 UIElements 都实现了 IInputElement,所以你应该可以路由到直接父级(在我的简单应用程序上试过这个,它从我的自定义控件回到主 window):
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
RoutedCommand c = e.Command as RoutedCommand;
IInputElement parent = this.Parent as IInputElement;
c.Execute(e.Parameter, parent);
}
我有一个 RoutedCommand 定义如下:
public static class Commands
{
/// <summary>
/// Represents the Foo feature of the program.
/// </summary>
public static readonly RoutedCommand Foo = new RoutedCommand("Foo", typeof(Window1));
}
然后我有一个用户控件,其命令定义如下:
<UserControl.CommandBindings>
<CommandBinding Command="{x:Static local:Commands.Foo}" Executed="CommandBinding_Executed"/>
</UserControl.CommandBindings>
<UserControl.InputBindings>
<KeyBinding Command="{x:Static local:Commands.Foo}" Modifiers="Control" Key="Space"></KeyBinding>
</UserControl.InputBindings>
并像这样用代码处理! (针对我的用户控件 class)
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Executed from sub");
}
我的自定义用户控件定义在我的主window:
<local:UserControl1 x:Name="myC" Grid.Row="1" DataContext="{Binding ChildName}"></local:UserControl1>
我的主要 window 也有自己处理 Foo 路由命令的方式:
CommandBindings.Add(new CommandBinding(Commands.Foo, new ExecutedRoutedEventHandler((x, y) => {
MessageBox.Show("Something Happend from main window");
})));
InputBindings.Add(new InputBinding(Commands.Foo, new KeyGesture(Key.P, ModifierKeys.Alt)));
现在,如果命令是从我的用户控件触发的,我希望事件冒泡到 window 如果 ExecutedRoutedEventArgs 的 Handled 属性 设置为 false,并且它是:
但只有来自用户控件的消息框会显示,我希望 window 上已处理事件的消息框会在之后显示!
谢谢
CommandBinding.Executed
事件的处理程序由 CommandBinding.OnExecuted
方法调用,该方法在处理程序完成后立即将 RoutedEventArgs.Handled
设置为 true
。该方法是内部方法而不是虚拟方法,因此您对此行为无能为力。
如果你真的想让父级处理命令,你可以从你的处理程序中调用它。这不是同一个命令,但会导致主程序 window 上的处理程序触发。
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
MessageBox.Show("Executed from sub");
var rc = e.Command as RoutedCommand;
var parentInput = FindParentInput();
if (parentInput != null && rc != null)
{
rc.Execute(null, parentInput);
}
}
private IInputElement FindParentInput()
{
DependencyObject element = this;
while (element != null)
{
DependencyObject parent = VisualTreeHelper.GetParent(element);
var input = parent as IInputElement;
if (input != null)
return input;
element = parent;
}
return null;
}
请注意,如果您尝试使用 null
作为第二个参数,它将再次向 this
相同的 UserControl 发送新命令。这就是为什么我包含了 FindParentInput
方法,该方法查找实现了“IInputElement”接口的最近的父级。
你可以做得更简单,似乎所有 UIElements 都实现了 IInputElement,所以你应该可以路由到直接父级(在我的简单应用程序上试过这个,它从我的自定义控件回到主 window):
private void CommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
RoutedCommand c = e.Command as RoutedCommand;
IInputElement parent = this.Parent as IInputElement;
c.Execute(e.Parameter, parent);
}