来自Enum的MVVM绑定

时间:2012-10-02 10:33:47

标签: wpf mvvm binding inotifypropertychanged

我正在开发我的第一个WPF / MVVM项目,而且我很难将我的大脑包围在一些事情上。这个项目将是一个已经在VB中制作的独立应用程序,因此所有逻辑和业务规则都已存在。

我遇到的问题是尝试实现绑定。我的应用程序上有几个按钮,它们的所有属性(IsEnabled,Text,image)都依赖于枚举。枚举基于状态并存在于模型中。

在VB应用程序中,我有一个巨大的switch语句来刷新按钮的属性,并且在状态可能改变的每个地方都调用它。所以对于这个版本,我根据状态为我的ViewModel中的每个按钮设置了一个bool和字符串,但是每次状态改变时都没有强制它更新(这很常见)。

我已经阅读了一些关于INotifyPropertyChanged的内容,但需要启动我的ViewModel中的更改的属性在我的模型中。我是以错误的方式解决这个问题吗?

4 个答案:

答案 0 :(得分:3)

我会在你的Button风格中使用DataTrigger。每当绑定值更新时,都会重新评估DataTrigger,并在必要时设置新值

<Style x:Key="MyButtonStyle" TargetType="{x:Type Button}">
    <Style.Triggers>
        <DataTrigger Binding="{Binding MyEnumProperty}" 
                     Value="{x:Static local:MyEnum.Value1}">
            <Setter Property="IsEnabled" Value="False" />
            <Setter Property="Content" Value="Value 1" />
        </DataTrigger>
        <DataTrigger Binding="{Binding MyEnumProperty}" 
                     Value="{x:Static local:MyEnum.Value2}">
            <Setter Property="IsEnabled" Value="True" />
        </DataTrigger>
    </Style.Triggers>
</Style>

您会对Image样式执行相同操作 - 根据状态枚举的当前值,在Image.Source中设置DataTrigger属性。

请记住,MyEnumProperty需要在更改时提出PropertyChange通知,以便UI知道值已更改并更新依赖于该值的任何绑定。

答案 1 :(得分:1)

我试图在WPF中搞砸enum的绑定,我不喜欢它很长时间。

您可以通过将属性映射到模型中的相应属性来解决此问题,在get方法中,您将依赖项实现到枚举的状态。

例如:

<Button  Height="41" HorizontalAlignment="Center" Style="{StaticResource ButtonStyle}"
                    Margin="407,77,289,0" Name="buttonSearch" VerticalAlignment="Top" Width="137" Click="search_click" 
                    IsEnabled="{Binding IsSearchButtonEnabled}" ...

说你有这个枚举:

public enum States
{
    StateOne,
    StateTwo,
    StateThree
}

在viewmodel中,您可以执行以下操作:

    public bool IsSearchButtonEnabled
    {
        get
        {
            return ((Model.actualState) == States.StateTwo);
        }
    }

要自动更新,ViewModel必须实现INotifyPropertyChanged。我使用一般实现,我的ViewModel总是子类化以简化事情。看起来像这样,每次调用InvokePropertyChanged(string propertyName)时都应该处理更新视图。 ViewModel需要知道它应该更新视图,它知道何时调用此方法。您可以在模型中使用相同的技术,并在模型中放置一个事件处理程序,通知订阅者VM状态枚举的setter中的更改。

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    public static event PropertyChangedEventHandler PropertyChangedStatic;

    public void InvokePropertyChanged(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public static void InvokePropertyChangedStatic(string propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChangedStatic;
        if (handler != null) handler(null, new PropertyChangedEventArgs(propertyName));
    }
} 

答案 2 :(得分:1)

在MVVM中,您实际上不应该直接从ViewModel引用View中的任何内容。

最佳解决方案是使用命令,例如MVVM-Light RelayCommand,它具有基于枚举属性值的CanExecute操作。然后,将按钮的命令属性bind绑定到ViewModel中的相应命令属性。这将自动设置按钮的启用状态。

然后在enum属性的set方法中,为每个命令调用CanExecuteChanged事件。

答案 3 :(得分:1)

您需要将每个IsEnabled的{​​{1}},TextImage属性绑定到viewmodel的Status属性。然后,您需要提供Button的3个实现,它们实际上将IValueConverter枚举值转换为您要查找的相应bool,字符串或图像。对于每个Status控件,请提供转换器可用于与viewmodel的Status属性进行比较的其他参数。

这样的事情:

Button

我不打算包含实现<myView.Resources> <local:statToBoolConverter x:Key="statToBoolConv" /> <local:statToTextConverter x:Key="statToTextConv" /> <local:statToImgConverter x:Key="statToImgConv" /> </myView.Resources> // ..... further down in code .... <Button x:Key="aButton" IsEnabled="{Binding Path=Status, Converter={StaticResource statToBoolConv}, ConverterParamter=caseA}" Text="{Binding Path=Status, Converter={StaticResource statToTextConv}, ConverterParamter=caseA}" Image="{Binding Path=Status, Converter={StaticResource statToImgConv}, ConverterParamter=caseA}"/> <Button x:Key="aButton" IsEnabled="{Binding Path=Status, Converter={StaticResource statToBoolConv}, ConverterParamter=caseB}" Text="{Binding Path=Status, Converter={StaticResource statToTextConv}, ConverterParamter=caseB}" Image="{Binding Path=Status, Converter={StaticResource statToImgConv}, ConverterParamter=caseB}"/> 的细节,因为它非常简单,但是你可以在这里获得更多信息(完整的例子):

http://msdn.microsoft.com/en-us/library/system.windows.data.ivalueconverter.aspx

还有一个注意事项:IValueConverter将触发所有按钮的绑定更新,因此进行单个INotifyPropertyChanged调用就可以了。