3

我正在处理我的第一个 WPF/MVVM 项目,我很难将我的大脑包裹在一些事情上。这个项目将是一个已经在 VB 中制作的东西的独立应用程序,所以所有的逻辑和业务规则都已经存在。

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

在 VB 应用程序中,我有一个巨大的 switch 语句来刷新按钮的属性,并且在状态可能改变的每个地方都会调用它。所以对于这个版本,我的 ViewModel 中的每个按钮都有一个 bool 和 string,基于状态,但没有办法在每次状态改变时强制它更新(这是相当频繁的)。

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

4

4 回答 4

3

我会DataTrigger在您的按钮样式中使用 a 。每当更新绑定值时,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风格做同样的事情 -根据 Status 枚举的当前值设置Image.Source属性。DataTrigger

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

于 2012-10-02T15:00:57.653 回答
1

我试图在 WPF 中弄乱与枚举的绑定,但我不太喜欢它。

您可以通过将属性映射到模型中的相应属性来解决此问题,在 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
}

在视图模型中,您可以这样做:

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

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

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));
    }
} 
于 2012-10-02T10:47:18.087 回答
1

您需要将每个属性的 、 和 属性绑定IsEnabledText视图Image模型Button的 Status 属性。然后,您需要提供 3 个实现,IValueConverter它们基本上将Status枚举值转换为您正在寻找的适当的布尔值、字符串或图像。对于每个Button控件,提供一个附加参数,转换器可以使用该参数与视图模型的 Status 属性进行比较。

像这样的东西:

<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}"/>

我不打算包括实现的细节,IValueConverter因为它非常简单,但您可以在此处获得更多信息(完整的示例):

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

还有一点需要注意:INotifyPropertyChanged将触发所有按钮的绑定更新,因此只需一次NotifyPropertyChanged("MyStatus")调用即可。

于 2012-10-02T13:49:41.937 回答
1

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

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

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

于 2012-10-02T13:12:36.247 回答