如何利用 MVVM Light EventToCommand 在 XAML 中绑定很多相同的事件?

How to take advantage of MVVM Light EventToCommand to bind a lot of same events in XAML?

让我解释一下我的要求:

我有一个包含多个复选框的网格,如下所示:

<Grid>

    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>

    <CheckBox>1</CheckBox>
    <CheckBox
        Grid.Column="1">2</CheckBox>
</Grid>

我清楚地知道如何使用 mvvm light EventToCommand 绑定到命令(在我的 VM 或其他任何地方定义)。 但是,众所周知,我有不止 1 个复选框。所以我必须这样做:

    <CheckBox
        Content="1">
        <i:Interaction.Triggers>
            <i:EventTrigger
                EventName="Checked">
                <ml:EventToCommand
                    Command="{Binding SomeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </CheckBox>
    <CheckBox
        Grid.Column="1"
        Content="2">
        <i:Interaction.Triggers>
            <i:EventTrigger
                EventName="Checked">
                <ml:EventToCommand
                    Command="{Binding SomeCommand}" />
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </CheckBox>

如果我有更多复选框,我必须一次又一次地 C+V 以使每个复选框具有相同的 EventToCommand 行为。 更烦人的是,我们还有另一个名为 Unchecked 的事件。通常 Checked 和 Uncheck 的回调是完全一样的。所以我不得不一次又一次的C+V.......

最后我的 XAML 又长又复杂!

=========================================== =

我正在考虑这样的解决方法:

我查看了Checked和Unchecked事件的源代码,发现它们都是RoutedEvent,模式为Bubble,这意味着这个路由事件调用冒泡到包含它们的网格。 所以我这样写 XAML 代码:

<Grid>  
    <i:Interaction.Triggers>
        <i:EventTrigger
            EventName="ToggleButton.Checked">
            <ml:EventToCommand
                Command="{Binding TestCommand}" />
        </i:EventTrigger>
    </i:Interaction.Triggers>
    ......several check boxes......
</Grid>

但是上面的代码是行不通的。 Checked 和 Unchecked 都不是 ATTACHED 事件。

然后我删除了"ToggleButton.",像这样:

        <i:EventTrigger
            EventName="Checked">
            <ml:EventToCommand
                Command="{Binding TestCommand}" />
        </i:EventTrigger>

还是不行! :(

事件应该在网格上冒泡,不是吗?

所以,有人对此有什么好的想法吗? 谢谢!

您可以为 Grid 中的所有 CheckBoxes 定义隐式 Style:

<Grid>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.Resources>
        <Style TargetType="CheckBox">
            <Setter Property="Command" Value="{Binding SomeCommand}" />
        </Style>
    </Grid.Resources>

    <CheckBox>1</CheckBox>
    <CheckBox Grid.Column="1">2</CheckBox>
</Grid>

而不是处理 CheckedUnchecked 事件,您可以将每个 CheckBoxIsChecked 属性 绑定到源 属性:

<CheckBox IsChecked="{Binding IsFirstChecked}">1</CheckBox>

感谢您的建议。这真的很方便。 我还在这个网站上找到了另一个解决方案 post: link 上面post中提到了另一种解决方案:

using System;
using System.Windows;
using System.Windows.Interactivity;

namespace NaiveMepUi.GuiCommon
{
public class RoutedEventTrigger : EventTriggerBase<DependencyObject>
{
    public RoutedEventTrigger() { }

    public RoutedEvent RoutedEvent { get; set; }

    protected override void OnAttached()
    {
        Behavior behavior = base.AssociatedObject as Behavior;
        FrameworkElement associatedElement =
            base.AssociatedObject as FrameworkElement;

        if (behavior != null)
        {
            associatedElement =
                ((IAttachedObject)behavior).AssociatedObject as FrameworkElement;
        }
        if (associatedElement == null)
        {
            throw new ArgumentException
                ("RoutedEventTrigger.AssociatedObject is not FrameworkElement.");
        }
        if (RoutedEvent != null)
        {
            associatedElement.AddHandler(
                RoutedEvent,
                new RoutedEventHandler(this.OnRoutedEvent));
        }
    }

    /// <summary>
    /// 路由事件被引发,继而引发基类的事件回调;
    /// 但是这一步会丢弃<paramref name="sender"/>。
    /// 如果事件绑定到命令,则命令只能接收到<paramref name="args"/>;
    /// 作为在 ViewModel 中定义的命令,原则上不应该 View 中定义的元素。
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="args"></param>
    void OnRoutedEvent(object sender, RoutedEventArgs args)
    {
        base.OnEvent(args);
    }

    protected override string GetEventName()
    {
        return RoutedEvent.Name;
    }
}
}

然后我可以像这样在 XAML 中使用它:

       <Grid>     
            <i:Interaction.Triggers>
                <guicommon:RoutedEventTrigger
                    RoutedEvent="CheckBox.Checked">
                    <ml:EventToCommand
                        Command="{Binding }" />
                    <!--todo 测试一下这种设计模式是否可行-->
                </guicommon:RoutedEventTrigger>
            </i:Interaction.Triggers>
       </Grid>