2012-10-02 63 views
3
綁定

我的工作我的第一個WPF/MVVM的項目,我有一個很難包裝我的大腦周圍的幾件事情。該項目將是的東西,已經在VB做了一個獨立的應用程序,因此,所有的邏輯和業務規則已經存在。MVVM從枚舉

我遇到的問題是試圖實現綁定。我的應用程序上有幾個按鈕,它們的所有屬性(IsEnabled,Text,image)都依賴於一個枚舉。枚舉基於狀態並存在於模型中。

在VB應用程序中,我有一個大規模的switch語句來刷新按鈕的屬性,並且在狀態可能發生變化的每個地方都會調用它。因此,對於這個版本,我已經在我的ViewModel每個按鈕基於狀態的布爾和字符串,但沒有辦法,迫使它更新每當狀態已經改變時(這是相當頻繁)。

我讀過一些關於INotifyPropertyChanged的內容,但需要啓動ViewModel中的更改的屬性位於我的模型中。我是否以這種錯誤的方式去做?

+1

絕對使用我(多)ValueConverter(s),不要凌亂您的ViewModel與按鈕的可見性/啓用狀態。 –

回答

1

你需要爲每個ButtonIsEnabledText,並且Image屬性綁定到視圖模型的狀態屬性。然後,您將需要提供基本上平移Status枚舉值到相應的布爾,字符串,或者你正在尋找形象IValueConverter的3個實現。對於每個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")調用就可以了。

+0

非常感謝@ code4life!實現了一個IMultiValueConverter,它完美地完成了這項工作:D – sporkful

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); 
     } 
    } 

要自動更新,您的視圖模型必須實現INotifyPropertyChanged。我使用ViewModel總是繼承的一般實現來簡化事情。它看起來像這樣,並且應該每次調用更新視圖調用InvokePropertyChanged(string propertyName)。 ViewModel需要知道它應該更新視圖,並知道何時調用此方法。您可以使用相同的技術在模型中,並放置在模型中的事件處理程序通知在國家枚舉的二傳手變化的用戶的VM。

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)); 
    } 
} 
+1

你說:「在模型中,你可以做到這一點:公共布爾IsSearchButtonEnabled」 理想情況下,該模型對UI或視圖模型一無所知。 我會在代表啓用搜索狀態(可能是布爾依賴項屬性)的視圖模型中實現一些內容,然後當模型中的狀態發生變化時,獲得OP提到的大量switch語句。 更好,在我看來是將狀態對象存儲在視圖模型中,然後當它從xaml更改爲設置按鈕狀態時使用觸發器。 –

+0

啊,所以模型對象需要在視圖的DataContext屬性中設置,如果這是你所缺少的。另外,模型需要實現INotifyPropertyChanged。 – Akku

+1

第三,您可以編寫一系列從狀態到需要的轉換器。 像,寫一個名爲MyEnumStateToButtonEnabled的轉換器,它接受枚舉類型並返回一個布爾值。 –

1

在MVVM中,你真的不應該直接從ViewModel引用視圖中的任何東西。

最好的解決方案是使用命令,如MVVM-Light RelayCommand,它具有基於enum屬性值的CanExecute操作。然後將該按鈕的命令屬性綁定綁定到ViewModel中相應的命令屬性。這會自動設置按鈕的啓用狀態。

然後在enum屬性的set方法中,爲每個命令調用CanExecuteChanged事件。

3

我會在你的按鈕樣式中使用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風格的新值設置 - 在基於當前什麼DataTrigger設置Image.Source財產Status枚舉的值是。

請記住,MyEnumProperty需要在PropertyChange通知發生更改時引發更改,以便UI知道該值已更改並更新依賴該值的任何綁定。

+0

對於'{x:Static ...'位 - 這是我試圖將綁定值綁定到枚舉值時丟失的鍵。謝謝! –