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

时间:2018-09-27 10:55:38

标签: c# wpf xaml mvvm mvvm-light

让我解释一下我的要求:

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

<Grid>

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

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

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

    <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漫长而复杂!

============================================= < / p>

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

我查看了Checked以及Unchecked事件的源代码,发现它们都是RoutedEvent,其模式为Bubble,这意味着此路由事件调用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>

但是上面的代码不起作用。选中事件和未选中都不是ATTACHED事件。

然后我删除了“ ToggleButton。”,就像这样:

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

仍然无法正常工作! :(

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

那么,有人对此有一些好的想法吗? 谢谢!

2 个答案:

答案 0 :(得分:0)

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

<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>

您可以将每个Checked的{​​{1}}属性绑定到源属性,而不是处理UncheckedIsChecked事件:

CheckBox

答案 1 :(得分:0)

感谢您的建议。真的很方便。 我还发现了另一个解决方案,该解决方案发布在此站点上: link 在以上帖子中,提到了另一种解决方案:

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>