给定:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.CommandBindings>
<CommandBinding Command="Cut"
Executed="CommandBinding_Executed"/>
</Grid.CommandBindings>
<TextBox x:Name="WpfTextBox"
VerticalAlignment="Center"
Text="Hello there" />
<WindowsFormsHost Grid.Column="1"
VerticalAlignment="Center">
<wf:TextBox x:Name="WinFormsTextBox"
Text="Hello there" />
</WindowsFormsHost>
</Grid>
在WinFormsTextBox
中按Ctrl+X会触发CommandBinding_Executed
,但在WpfTextBox
中时不会触发。
我希望有WpfTextBox
对WinFormsTextBox
的行为。也就是说,该命令应该只在没有焦点的情况下启动——它应该像全局视图命令或其他命令一样工作
注意:在命令的CanExecute
事件中添加一个处理程序只有助于防止WinFormsTextBox
中发生任何事情(当e.CanExecute
设置为true
时,Ctrl+X被完全吞噬,这意味着没有剪切文本(,或者正常执行。
注意2:Cut只是一个例子,我想要一个适用于任何命令绑定的解决方案。
注意3:如果命令有焦点,比如ListView之类的,那么它应该能够从另一个控件激发。除非它有一个文本框,里面有焦点(想想编辑模式(。
我不确定真的能做什么,我不想接受必须在CommandBinding_Executed
方法中添加特定的处理。但是,这是生活。
WPF命令被路由,并且您在WindowsFormsHost的父控件中为Ctrl+X命令定义了CommandBinding。因此,如果你想只在WPF文本框中处理它,请从网格中删除CommandBinding并将其放在那里:
<TextBox>
<TextBox.CommandBindings>
<CommandBinding Command="Cut"
Executed="CommandBinding_Executed"/>
</TextBox.CommandBindings>
</TextBox>
在路由命令时,Ctrl+X命令将由具有该命令绑定的第一个父级处理。只要您的焦点在网格的范围内,并且您执行Ctrl+X命令,网格命令绑定就会处理它。
这是一篇关于WPF中路由事件和命令的优秀文章:了解WPF 中的路由事件和指令
编辑:
如果您不希望在TextBox中处理命令,则必须仅在Ctrl+X对您有意义的地方定义CommandBindings。我认为你没有其他解决方案。无论如何,像Cut这样的ApplicationCommands通常是与特定范围相关的,例如RichTextBox或ListBox。
编辑:
不能阻止WindowsFormsHost激发基础路由命令。但您所能做的只是将主机从CommandBindings作用域中删除:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid Grid.Column="0">
<Grid.CommandBindings>
<CommandBinding Command="Cut"
Executed="CommandBinding_Executed"/>
</Grid.CommandBindings>
<TextBox x:Name="WpfTextBox"
VerticalAlignment="Center"
Text="Hello there" />
</Grid>
<WindowsFormsHost Grid.Column="1"
VerticalAlignment="Center">
<wf:TextBox x:Name="WinFormsTextBox"
Text="Hello there" />
</WindowsFormsHost>
</Grid>
当然,如果你有更多的对象要布局,这可能有点棘手,但它会起作用。只需从CommandBindings的作用域中删除不想处理命令的对象。
一个稍微愚蠢的问题的稍微愚蠢的解决方案。这是我最终解决方案的一个简单版本:
private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
{
e.ContinueRouting = IsFocusInWinFormsInputControl();
}
private static bool IsFocusInWinFormsInputControl()
{
// Try get focus control
WinForms.Control focusedWinFormsControl = GetFocusedWinFormsControl();
// Is there anything and is it a textbox etc?
return focusedWinFormsControl != null &&
(focusedWinFormsControl is WinForms.TextBox ||
focusedWinFormsControl is WinForms.RichTextBox);
}
private static WinForms.Control GetFocusedWinFormsControl()
{
// Try get focused WinForms control
IntPtr focusedControlHandle = GetFocus();
WinForms.Control focusedControl = null;
if (focusedControlHandle != IntPtr.Zero)
{
// Note: If focused Control is not a WinForms control, this will return null
focusedControl = WinForms.Control.FromHandle(focusedControlHandle);
}
return focusedControl;
}
[DllImport("user32.dll")]
private static extern IntPtr GetFocus();
基本上,添加命令验证逻辑,仅当我们在WinForms TextBox之外时才执行命令。