Как предотвратить 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>