C# Silverlight MVVM混淆:基于状态更新映像

C# Silverlight MVVM混淆:基于状态更新映像,c#,mvvm,silverlight-4.0,C#,Mvvm,Silverlight 4.0,我正在开发一个Silverlight应用程序,并试图坚持MVVM原则,但在根据ViewModel中属性的状态更改图像源时遇到了一些问题。无论出于何种目的,您都可以将我正在实现的功能想象为音频应用程序的播放/暂停按钮。在“播放”模式下,ViewModel中的IsActive为真,按钮上的“Pause.png”图像应显示出来。暂停时,ViewModel中的IsActive为false,按钮上显示“Play.png”。当然,当鼠标悬停在按钮上时,还有两个额外的图像需要处理 我想我可以使用,但显然Sil

我正在开发一个Silverlight应用程序,并试图坚持MVVM原则,但在根据ViewModel中属性的状态更改图像源时遇到了一些问题。无论出于何种目的,您都可以将我正在实现的功能想象为音频应用程序的播放/暂停按钮。在“播放”模式下,ViewModel中的IsActive为真,按钮上的“Pause.png”图像应显示出来。暂停时,ViewModel中的IsActive为false,按钮上显示“Play.png”。当然,当鼠标悬停在按钮上时,还有两个额外的图像需要处理

我想我可以使用,但显然Silverlight不支持它们。我一直在查看一篇论坛帖子,其中有一个问题与我的问题类似,建议使用。虽然这可能有助于更改悬停/正常状态的图像,但缺少的部分(或者我不理解)是如何通过视图模型处理状态集。这篇文章似乎只适用于事件,而不是视图模型的属性。话虽如此,我也没有成功完成正常/悬停效果

下面是我的Silverlight 4 XAML。还应该注意的是,我正在使用MVVM Light

<UserControl x:Class="Foo.Bar.MyUserControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    mc:Ignorable="d"
    d:DesignHeight="100" d:DesignWidth="200">
    <UserControl.Resources>
        <Style x:Key="MyButtonStyle" TargetType="Button">
            <Setter Property="IsEnabled" Value="true"/>
            <Setter Property="IsTabStop" Value="true"/>
            <Setter Property="Background" Value="#FFA9A9A9"/>
            <Setter Property="Foreground" Value="#FF000000"/>
            <Setter Property="MinWidth" Value="5"/>
            <Setter Property="MinHeight" Value="5"/>
            <Setter Property="Margin" Value="0"/>
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalAlignment" Value="Top" />
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Cursor" Value="Hand"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Button">
                        <Grid>
                            <Image Source="/Foo.Bar;component/Resources/Icons/Bar/Play.png">
                                <VisualStateManager.VisualStateGroups>
                                    <VisualStateGroup x:Name="Active">
                                        <VisualState x:Name="MouseOver">
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Source" Storyboard.TargetName="/Foo.Bar;component/Resources/Icons/Bar/Play_Hover.png" />
                                            </Storyboard>
                                        </VisualState>
                                    </VisualStateGroup>
                                </VisualStateManager.VisualStateGroups>
                            </Image>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <Button Style="{StaticResource MyButtonStyle}" Command="{Binding ChangeStatus}" Height="30" Width="30" />
    </Grid>
</UserControl>


使用视图模型确定的状态更新按钮上的图像的正确方法是什么?

一种简单的方法是,将VM上的IsActive和IsNotActive布尔属性绑定到按钮内容内两个图像控件上的可见性

当然,您必须使用BooleanToVisiblityConverter


第二个想法:你能不能将iActive绑定到你按钮上的iEnabled,让样式显示正确的图像。不确定您在Silverlight中提到的限制是否会阻止这一点。

我们有一些自定义转换器,可以将布尔值(和其他类型)更改为特定图像。这样,视图/模型就尽可能分开

转换器很容易编写,网上有很多例子

因此,在xaml中,它是这样的:

<Image Source={Binding IsActive, Converter={StaticResource "boolToPlayImageConverter"}}/>

通过一位同事的建议,由于我已经在使用,我能够利用来处理视图模型中的鼠标进入和鼠标离开事件,而不是依赖内置的VisualStateManager来处理这些事件。我还将我的按钮更改为ToggleButton。这使我能够利用选中和未选中状态来处理是显示播放按钮还是暂停按钮。由于状态由视图模型控制,因此我可以通过将ToggleButton的可见性属性绑定到视图模型上检查状态的属性来确定要显示的图像。我更新的XAML如下所示:

<UserControl x:Class="Foo.Bar.MyControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:i="clr-namespace:System.Windows.Interactivity;assembly=System.Windows.Interactivity"
    xmlns:cmd="clr-namespace:GalaSoft.MvvmLight.Command;assembly=GalaSoft.MvvmLight.Extras.SL4"
    mc:Ignorable="d"
    d:DesignHeight="100" d:DesignWidth="200">
    <i:Interaction.Triggers>
        <i:EventTrigger EventName="MouseEnter">
            <cmd:EventToCommand Command="{Binding MouseEnterCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
        <i:EventTrigger EventName="MouseLeave">
            <cmd:EventToCommand Command="{Binding MouseLeaveCommand}" PassEventArgsToCommand="True"/>
        </i:EventTrigger>
    </i:Interaction.Triggers>
    <UserControl.Resources>
        <Style x:Key="MyButtonStyle" TargetType="ToggleButton">
            <Setter Property="IsEnabled" Value="true"/>
            <Setter Property="IsTabStop" Value="true"/>
            <Setter Property="Background" Value="#FFA9A9A9"/>
            <Setter Property="Foreground" Value="#FF000000"/>
            <Setter Property="MinWidth" Value="5"/>
            <Setter Property="MinHeight" Value="5"/>
            <Setter Property="Margin" Value="0"/>
            <Setter Property="HorizontalAlignment" Value="Left" />
            <Setter Property="HorizontalContentAlignment" Value="Center"/>
            <Setter Property="VerticalAlignment" Value="Top" />
            <Setter Property="VerticalContentAlignment" Value="Center"/>
            <Setter Property="Cursor" Value="Hand"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="ToggleButton">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CheckStates">
                                    <VisualState x:Name="Checked">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Pause">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Play">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Collapsed</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Unchecked">
                                        <Storyboard>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Play">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Visible</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                            <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Pause">
                                                <DiscreteObjectKeyFrame KeyTime="0">
                                                    <DiscreteObjectKeyFrame.Value>
                                                        <Visibility>Collapsed</Visibility>
                                                    </DiscreteObjectKeyFrame.Value>
                                                </DiscreteObjectKeyFrame>
                                            </ObjectAnimationUsingKeyFrames>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Indeterminate" />
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Image x:Name="Play" Source="/Foo.Bar;component/Resources/Icons/Bar/Play.png" />
                            <Image x:Name="Pause" Source="/Foo.Bar;component/Resources/Icons/Bar/Pause.png" Visibility="Collapsed" />
                            <Image x:Name="PlayHover" Source="/Foo.Bar;component/Resources/Icons/Bar/Play_Hover.png" Visibility="{Binding PlayHoverVisible,FallbackValue=Collapsed}" />
                            <Image x:Name="PauseHover" Source="/Foo.Bar;component/Resources/Icons/Bar/Pause_Hover.png" Visibility="{Binding PauseHoverVisible,FallbackValue=Collapsed}" />
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <ToggleButton Style="{StaticResource MyButtonStyle}" IsChecked="{Binding IsPlaying}" Command="{Binding ChangeStatus}" Height="30" Width="30" />
    </Grid>
</UserControl>

看得见的
崩溃
看得见的
崩溃