Как предотвратить InvokeCommandAction от распространения события на родительские элементы?

Я понял, что при использовании InvokeCommandAcction, связанного с EventTrigger, исходное событие все еще направлялось до родительских элементов, пока оно не было обработано. Ну, я думаю, это ожидаемое поведение. Но мой вопрос заключается в том, как я могу пометить событие как Обработанное, чтобы оно не распространялось вверх по всему дереву пользовательского интерфейса?

На самом деле, когда вы обрабатываете это событие в команде, в этой команде все будет обрабатываться, поэтому распространять ее не нужно. И в одном случае, который я обнаружил, это вызывает нежелательное поведение. Например, я открываю новое окно, когда пользователь дважды щелкает элемент (событие MouseDoubleClick). Проблема в том, что новые окна открываются, а затем главное окно возвращается перед новым, потому что событие MouseDoubleClick только что достигло верхнего элемента в дереве пользовательского интерфейса. Требуемым поведением было бы сохранение нового окна впереди, но поскольку InvokeCommandAction позволяет событию распространяться вверх, главное окно возвращает фокус...

Вместо этого я мог бы использовать актив CallMethodAction, но, поскольку я нахожусь в сценарии MVVM, я не хочу, чтобы в моем коде были аргументы событий пользовательского интерфейса. Даже если это позволит мне неявно пометить событие как обработанное и устранить проблему.

<UserControl x:Class="..."
             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseDoubleClick">
            <i:InvokeCommandAction Command="{Binding Path=DisplayReportCommand}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    ...
</UserControl>

3 ответа

Решение

Вы можете реализовать свой собственный EventTrigger, который помечает события как обработанные.

public class HandlingEventTrigger : System.Windows.Interactivity.EventTrigger
{
    protected override void OnEvent(System.EventArgs eventArgs)
    {
        var routedEventArgs = eventArgs as RoutedEventArgs;
        if (routedEventArgs != null)
            routedEventArgs.Handled = true;

        base.OnEvent(eventArgs);
    }
}

Затем заменить <i:EventTrigger EventName="MouseDoubleClick"> с <local:HandlingEventTrigger EventName="MouseDoubleClick"> и добавить

xmlns:local="clr-namespace:HandlingEventTrigger's namespace here"

к атрибутам вашего usercontrol.

Добавить прикрепленное событие в пользовательский элемент управления

              CommandManager.PreviewCanExecute="PreviewCanExecute" 

и в обработчике событий

               e.ContinueRouting = false;

Надеюсь, это поможет!

Событие MouseDoubleClick на самом деле является не пузырьковым перенаправленным событием, а прямым перенаправленным событием.

Однако это событие возникает вдоль дерева элементов, что можно проверить с помощью инструмента Snoop. Более того, даже если для параметра Handled for MouseDoubleClick установлено значение true, это событие будет происходить вдоль дерева элементов.

Хотя это перенаправленное событие (MouseDoubleClick Event), по-видимому, следует по пузырчатому маршруту через дерево элементов, на самом деле это событие с прямой маршрутизацией, которое вызывается вдоль дерева элементов каждым элементом UIElement.

Если для свойства Handled установлено значение true в обработчике события MouseDoubleClick, последующие события MouseDoubleClick вдоль маршрута будут происходить, а для параметра Handled установлено значение false. Это событие более высокого уровня для потребителей элементов управления, которые хотят получать уведомления, когда пользователь дважды щелкает элемент управления и обрабатывает событие в приложении. (Из MSDN)

Как указано выше, ваша проблема может быть не вызвана распространением, как вы упоминали. Существует свойство Window.ShowActivation, которое определяет, активируется ли окно при первом показе. Вы можете установить свойство в подокне (xaml), как показано ниже, но имейте в виду, что хотя ShowActivation может дать фокус главному окну, оно не может позволить главному окну визуально находиться перед подокном. Я пытался найти решение, но понятия не имею до сих пор.

<Window ShowActivated="False" ....>
....
</Window>
Другие вопросы по тегам