0

鉴于:

<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>

Ctrl+ XinWinFormsTextBoxCommandBinding_Executed触发,但在WpfTextBox.

我希望有WpfTextBoxfor的行为WinFormsTextBox。即命令应该只在没有焦点时触发 - 它应该像全局视图命令或其他东西一样工作。

注意:向命令的CanExecute事件添加处理程序仅有助于防止任何事情发生WinFormsTextBox(当设置为- 时, Ctrl+X被完全吞没,意味着没有文本被剪切),或者正常执行。e.CanExecutetrue

注意 2:Cut 只是一个示例,我想要一个适用于任何命令绑定的解决方案。

注意 3:该命令应该能够从另一个控件触发,如果它有焦点 - 比如 ListView 或其他东西。除非它有一个在其中有焦点的文本框(想想编辑模式)。

我不确定是否真的可以做任何事情,我不想接受必须在CommandBinding_Executed方法中添加特定处理。但是,C'est la vie。

4

2 回答 2

0

WPF 命令已路由,并且您在 WindowsFormsHost 的父控件中为 Ctrl+X 命令定义了 CommandBinding。因此,如果您希望仅在 WPF TextBox 中处理它,请从 Grid 中删除您的 CommandBinding 并将其放在那里:

<TextBox>    
    <TextBox.CommandBindings>
        <CommandBinding Command="Cut" 
                        Executed="CommandBinding_Executed"/>
    </TextBox.CommandBindings>
</TextBox>

路由命令时,Ctrl+X 命令将由具有此命令绑定的第一个父级处理。只要您的焦点在 Grid 范围内并且您执行 Ctrl+X 命令,Grid 命令绑定就会处理它。


这是一篇关于 WPF 中路由事件和命令的优秀文章:Understanding Routed Events and Commands In 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 的范围中删除您不想处理命令的对象。

于 2011-09-22T11:13:49.367 回答
0

一个稍微愚蠢的问题的稍微愚蠢的解决方案。这是我最终解决方案的简单版本:

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 文本框之外时执行命令。

于 2011-09-26T09:29:09.527 回答