Применение Interaction EventTrigger для каждого элемента управления типа в представлении

У меня есть представление, в котором я обрабатываю всю навигацию по приложению. Теперь я хочу добавить EventTrigger ко всем элементам управления типа <vw:NavigationRadioButton/>.

<vw:NavigationRadioButton Text="Frisse Conche" RegionName="MainRegion" ViewName="PanoramaFrisse">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="PreviewMouseDown">
        <i:InvokeCommandAction Command="{Binding Path=CheckRecipeChangedCommand, Source={vw:AdapterBinding RecipeAdapter}}" CommandParameter="MainRegion;PanoramaFrisse"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</vw:NavigationRadioButton>

Кроме того, если это возможно: я хочу передать значение свойств RegionName и ViewName моей команде (как я сделал вручную в этом примере)

Если это возможно, как я могу это сделать?


person user2877820    schedule 20.11.2017    source источник
comment
добавить ... ко всем элементам управления типа = style с помощью TargetType. Однако никогда не использовал Blend.   -  person Sinatr    schedule 20.11.2017
comment
@Sinatr К сожалению, коллекции Interaction.Behaviors и Interaction.Triggers нельзя использовать из Style, поскольку они доступны только для чтения (такая же проблема существует, например, для Grid.ColumnDefinitions).   -  person Grx70    schedule 20.11.2017
comment
@Grx70, выполнимо.   -  person Sinatr    schedule 20.11.2017


Ответы (1)


Обычное решение таких проблем заключается в использовании правильного (обычно неявного) Style. К сожалению, невозможно заполнить Interaction.Behaviors или Interaction.Triggers с помощью стиля1. По крайней мере, не напрямую, хотя существуют некоторые обходные пути, такие как этот упомянул @Sinatr в своем комментарии.

Однако, на мой взгляд, лучшим решением является создание выделенного вспомогательного класса с прикрепленным свойством, которое дополнительно позволит вам убить двух зайцев одним выстрелом и передать правильный параметр в команду:

public static class NavigationRadioButtonHelper
{
    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.RegisterAttached(
            name: "Command",
            propertyType: typeof(ICommand),
            ownerType: typeof(NavigationRadioButtonHelper),
            defaultMetadata: new PropertyMetadata(null, HandleCommandChanged));

    public static ICommand GetCommand(NavigationRadioButton control)
        => (ICommand)control.GetValue(CommandProperty);

    public static void SetCommand(NavigationRadioButton control, ICommand value)
        => control.SetValue(CommandProperty, value);

    private static void HandleCommandChanged(
        DependencyObject d,
        DependencyPropertyChangedEventArgs e)
    {
        if (e.NewValue != null)
        {
            ((NavigationRadioButton)d).AddHandler(
                routedEvent: Mouse.PreviewMouseDownEvent,
                handler: (MouseButtonEventHandler)HandlePreviewMouseDown);
        }
        else
        {
            ((NavigationRadioButton)d).RemoveHandler(
                routedEvent: Mouse.PreviewMouseDownEvent,
                handler: (MouseButtonEventHandler)HandlePreviewMouseDown);
        }
    }

    private static void HandlePreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        var control = (NavigationRadioButton)sender;
        var command = GetCommand(control);
        var parameter = $"{control.RegionName},{control.ViewName}";
        if (command != null && command.CanExecute(parameter))
            command.Execute(parameter);
    }
}

Здесь происходит следующее: когда свойству назначается команда, к связанному объекту добавляется обработчик Mouse.PreviewMouseDownEvent, который просто выполняет прикрепленную команду, одновременно удобно создавая требуемый параметр. Когда для команды установлено значение null, обработчик удаляется. И поскольку эта функциональность зависит исключительно от одного прикрепленного свойства зависимости, ее можно легко использовать в сочетании со стилем:

<Style TargetType="{x:Type vw:NavigationRadioButton}">
    <Setter Property="ns:NavigationRadioButtonHelper.Command" Value="{Binding (...)}" />
</Style>

Я предполагаю, что у вас нет права изменять класс NavigationRadioButton, и в этом случае эта логика может быть включена в этот класс без необходимости во вспомогательном классе.


1 Коллекции, как правило, не могут быть заполнены с помощью стиля, только назначены. Ни одно из этих двух свойств не является общедоступным, и у них нет общедоступных методов установки, и поэтому их можно считать доступными только для чтения в том смысле, что их значения не могут быть присвоены, а только изменены.

person Grx70    schedule 20.11.2017