MVVM绑定到CLR事件

kev*_*vin 4 clr events binding mvvm

你如何使用mvvm模式绑定到CLR事件?

对于路由事件,我使用Cinch框架中的EventToCommandTrigger,这非常有用.

我查看了Expression Blend Samples中的Behaviors和Effects,看起来我应该使用DataEventTrigger,但样本有点令人困惑.

我希望IsVisibleChanged事件触发我的IsVisibleChangedCommand.我也不确定在ViewModel中需要使用哪些代码来支持它.

<i:Interaction.Triggers>

    <i:EventTrigger EventName="SelectedItemChanged">
        <framework:EventToCommandTrigger Command="{Binding SelectedMenuItemChangedCommand}"
                                        CommandParameter="{Binding SelectedValue, ElementName=lstClusters}" />
    </i:EventTrigger>

    <framework:DataEventTrigger EventName="IsVisibleChanged"
                            Source="{Binding IsVisibleChangedCommand}">
    </framework:DataEventTrigger>

</i:Interaction.Triggers>
Run Code Online (Sandbox Code Playgroud)

Har*_*ess 7

您可以使用Expression Blend SDK来调用命令以响应一般事件,但我的经验是,并非EventTrigger支持所有事件.

例如,这似乎有效:

<Label Content="LabelText">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseMove">
            <i:InvokeCommandAction Command="{Binding IsVisibleChangedCommand, Mode=OneWay}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Label>
Run Code Online (Sandbox Code Playgroud)

但这不是:

<Label Content="LabelText">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="IsVisibleChanged">
            <i:InvokeCommandAction Command="{Binding IsVisibleChangedCommand, Mode=OneWay}"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
</Label>
Run Code Online (Sandbox Code Playgroud)

我不知道为什么,但Blend SDK似乎不喜欢IsVisible属性.您可以执行类似的操作,但使用Visibility(而不是IsVisible)和PropertyChangedTrigger,如下所示:

<Label x:Name="label1" Content="LabelText">
    <i:Interaction.Triggers>
        <ei:PropertyChangedTrigger Binding="{Binding Visibility, ElementName=label1}">
            <i:InvokeCommandAction Command="{Binding IsVisibleChangedCommand, Mode=OneWay}"/>
        </ei:PropertyChangedTrigger>
    </i:Interaction.Triggers>
</Label>
Run Code Online (Sandbox Code Playgroud)

BTW - 以下是命名空间:

xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
Run Code Online (Sandbox Code Playgroud)

此外,这是您的特定问题的另一个解决方案,不需要Blend SDK:

您可以将对象的Visibility属性绑定到viewmodel属性,而不是直接将事件绑定到命令,并从属性setter执行命令,如下所示:

视图:

<UserControl x:Class="SampleApp.Views.EventBindingDemoView"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             Height="200" Width="200">
    <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
    </UserControl.Resources>
    <Grid>
        <Label Content="LabelText" Visibility="{Binding Path=ElementIsVisible, Mode=TwoWay, Converter={StaticResource BooleanToVisibilityConverter}}"/>

        <!-- The rest of your view here -->

    </Grid>
</UserControl>
Run Code Online (Sandbox Code Playgroud)

ViewModel(ViewModelBase应该实现INotifyPropertyChanged和OnPropertyChanged(string propertyName)):

public class EventBindingDemoViewModel : ViewModelBase
{
    private bool ElementIsVisibleField = true; // or false if it should initially be hidden
    public bool ElementIsVisible
    {
        get { return this.ElementIsVisibleField; }
        set
        {
            if (this.ElementIsVisibleField != value)
            {
                this.ElementIsVisibleField = value;
                this.OnPropertyChanged("ElementIsVisible");

                // Execute command
                this.IsVisibleChangedCommand.Execute(null);
            }
        }
    }

    public ICommand IsVisibleChangedCommand;

    // The rest of your viewmodel here
}
Run Code Online (Sandbox Code Playgroud)

无论哪种方式都应该有效.

  • 请注意,IsVisible和Visibility不一定是相同的:"确定IsVisible值会考虑布局的所有因素.相比之下,Visibility是一个可设置的属性,仅表示以编程方式使元素可见或不可见的意图. " (2认同)