WPF-команды запускаются, несмотря на то, что у них есть фокус в WinForms TextBox - PullRequest
0 голосов
/ 22 сентября 2011

Дано:

<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 + X в WinFormsTextBox заставляет CommandBinding_Executed срабатывать, но не тогда, когда вы находитесь в WpfTextBox.

Я хотел бы иметь поведение WpfTextBox для WinFormsTextBox. То есть Команда должна срабатывать только тогда, когда ничто не имеет фокуса - она ​​должна работать как команда глобального вида или что-то в этом роде.

Примечание. Добавление обработчика к событию CanExecute команды только помогает предотвратить возникновение чего-либо в WinFormsTextBox ( Ctrl + X полностью проглатывается при e.CanExecute установлен на true - означает, что текст не обрезан) или работает как обычно.

Примечание 2: Cut - это только пример, я хотел бы, чтобы решение работало для любой привязки команды.

Примечание 3: команда должна запускаться из другого элемента управления, если он имеет фокус - например, ListView или что-то в этом роде. Если у него не было TextBox, в котором был фокус (режим редактирования).

Я не уверен, что что-то действительно можно сделать, я не хочу соглашаться с необходимостью добавить определенную обработку в методе CommandBinding_Executed. Но, C'est la vie.

Ответы [ 2 ]

0 голосов
/ 26 сентября 2011

Немного глупое решение для слегка глупой проблемы. Это простая версия моего окончательного решения:

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.

0 голосов
/ 22 сентября 2011

Команды WPF маршрутизируются, и вы определили привязку CommandBinding для команды Ctrl + X в родительском элементе управления WindowsFormsHost. Поэтому, если вы хотите, чтобы он обрабатывался только в текстовом поле WPF, удалите привязку CommandBinding из таблицы и поместите ее туда:

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

Когда команды маршрутизируются, команда Ctrl + X будет обрабатываться первым родителем, имеющим привязку для этой команды. Пока ваш фокус находится в области действия Grid и вы выполняете команду Ctrl + X, привязки команды Grid будут обрабатывать ее.


Вот отличная статья о перенаправленных событиях и командах в WPF: Понимание перенаправленных событий и команд в WPF


EDIT:

Если вы не хотите, чтобы команда обрабатывалась в TextBox, тогда вы должны определять CommandBindings только там, где Ctrl + X имеет для вас смысл. Я не думаю, что у вас есть другое решение. В любом случае, как правило, ApplicationCommands, такие как Cut, контекстуальны для определенной области, например RichTextBox или ListBox.


EDIT:

Нельзя блокировать 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.

...