尽管WinForms文本框中有焦点,WPF命令仍在激发



给定:

<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中时不会触发。

我希望有WpfTextBoxWinFormsTextBox的行为。也就是说,该命令应该只在没有焦点的情况下启动——它应该像全局视图命令或其他命令一样工作

注意:在命令的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之外时才执行命令。

相关内容

  • 没有找到相关文章

最新更新