2014-07-11 25 views
0

我已將我的組框綁定到INotifyPropertyChanged類。從XAML中的頁面綁定中獲取或設置INotifyPropertyChanged類的屬性值

頁面資源

<Page.Resources> 
     <current:UserAccountsStatusHandler x:Key="UserAccounts" /> 
    </Page.Resources> 

組框

<GroupBox 
       Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2" 
       Header="Select Action:" 
       Foreground="{DynamicResource DynamicFrmFG}" 
       VerticalAlignment="Stretch" HorizontalAlignment="Left" 
       Height="50" 
       DataContext="{StaticResource ResourceKey=UserAccounts}"> 

       <StackPanel 
        Orientation="Horizontal" 
        HorizontalAlignment="Stretch" VerticalAlignment="Center" 
        Height="Auto"> 
        <RadioButton 
         Content="Insert" 
         Foreground="{DynamicResource DynamicFrmFG}" Height="16" 
         IsChecked="{Binding Path=UserAccountAction, Converter={StaticResource enumToBooleanConverter}, 
            ConverterParameter={x:Static enums:UserAccountActions.Insert}, UpdateSourceTrigger=PropertyChanged}" 
         Margin="0,0,10,0" 
         Click="RadioButton_Click" /> 
        <RadioButton 
         Content="Update" 
         Foreground="{DynamicResource DynamicFrmFG}" Height="16" 
         IsChecked="{Binding Path=UserAccountAction, Converter={StaticResource enumToBooleanConverter}, 
            ConverterParameter={x:Static enums:UserAccountActions.Update}, UpdateSourceTrigger=PropertyChanged}" 
         Margin="0,0,10,0" 
         Click="RadioButton_Click" /> 
        <RadioButton 
         Content="Delete" 
         Foreground="{DynamicResource DynamicFrmFG}" Height="16" 
         IsChecked="{Binding Path=UserAccountAction, Converter={StaticResource enumToBooleanConverter}, 
            ConverterParameter={x:Static enums:UserAccountActions.Delete}, UpdateSourceTrigger=PropertyChanged}" 
         Margin="0,0,10,0" 
         Click="RadioButton_Click" /> 
       </StackPanel> 
      </GroupBox> 

public class UserAccountsStatusHandler : INotifyPropertyChanged 
{ 
    private UserAccountActions userAccountAction; 
    public UserAccountActions UserAccountAction 
    { 
     get { return userAccountAction; } 
     set 
     { 
      userAccountAction = value; 
      IsSaveEnabled = (userAccountAction == UserAccountActions.None) ? false : true; 
      OnPropertyChanged("UserAccountAction"); 
     } 
    } 

    private bool isSavedEnabled; 
    public bool IsSaveEnabled { get { return isSavedEnabled; } set { isSavedEnabled = value; OnPropertyChanged("IsSaveEnabled"); } } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 
} 

這一切工作如預期。我點擊其中一個單選按鈕並更改屬性,保存按鈕變爲啓用狀態。然而,我想知道如何從類中取出這些值,在頁面後面的代碼中,實際上不必從UI中拉出組合框的DataContext,然後調用該類。

如果我嘗試在頁面後面的代碼中創建類的新實例,如預期的那樣,我會得到默認值。到目前爲止,我已經發現瞭如何獲取/設置值的唯一方法是通過設置變量的值等於groupboxes的DataContext像這樣:

 var test = (UserAccountsStatusHandler)tempGroupBoxName.DataContext; 
     test.IsSaveEnabled = false; 

很多事情我已經閱讀狀態下的數據層應永遠不需要知道有關UI的任何信息。所以我不知道如何做到這一點。任何幫助將不勝感激。

編輯:添加我以前做過的事情,我認爲也是錯誤的。

private UserAccountsStatusHandler mainStatusHandler; 
mainStatusHandler = new UserAccountsStatusHandler();    
base.DataContext = mainStatusHandler; 

在這一點上,我可以方便地調用mainStatusHandler得到的東西喜歡的是IsSavedEnabled並確定用戶從UserAccountAction選擇什麼樣的行動。我使用IsSavedEnabled的唯一真正原因是在標籤重新加載頁面時禁用按鈕。要確保他們沒有實際選擇一個動作,然後啓用保存按鈕,就不會點擊保存按鈕。然後他們必須實際點擊保存按鈕來執行後面的代碼以將數據保存到服務器。

+0

根據迄今爲止提供的答案,我可能需要更多地閱讀MVVM。我可能沒有像我想的那樣抓住它。 – famousKaneis

+0

我更新了我的答案,爲您提供了一個更適合您的需求的例子。從你的編輯中,很清楚你只需要刷新MVVM和WPF。你不應該把這種東西放在你的代碼後面,它真的屬於視圖模型。 –

回答

1

由於您只是將其用於某種形式的驗證,所以您確實需要使用ICommand實現。因此,在這種情況下,修改視圖模型以在INotifyPropertyChanged的旁邊實現ICommand接口。

public class UserAccountsStatusHandler : INotifyPropertyChanged, ICommand 
{ 
    private UserAccountActions userAccountAction; 
    public UserAccountActions UserAccountAction 
    { 
     get { return userAccountAction; } 
     set 
     { 
      userAccountAction = value; 
      IsSaveEnabled = (userAccountAction == UserAccountActions.None) ? false : true; 
      OnPropertyChanged("UserAccountAction"); 

      // Refresh the CanExecute method. 
      OnCanExecuteChanged(); 
     } 
    } 

    private bool isSavedEnabled; 
    public bool IsSaveEnabled { get { return isSavedEnabled; } set { isSavedEnabled = value; OnPropertyChanged("IsSaveEnabled"); } } 

    public event PropertyChangedEventHandler PropertyChanged; 
    private void OnPropertyChanged(string propertyName) 
    { 
     if (this.PropertyChanged != null) 
      this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    public bool CanExecute(object parameter) 
    { 
     return userAccountAction.SomeActionSelected != null; 
    } 

    public event EventHandler CanExecuteChanged; 
    private void OnCanExecuteChanged() 
    { 
     if (this.CanExecuteChanged!= null) 
      this.CanExecuteChanged(this, new EventArgs()); 
    } 

    public void Execute(object parameter) 
    { 
     // perform save code. 
    } 
} 
在XAML

現在,如果你的組合框中有一個UserAccountStatusHandler作爲其數據的上下文,您可以使用您分配一個分組框中的名稱,你的按鈕綁定到它。

<GroupBox x:Name="UserAccountStatusGroupBox"></GroupBox> 

<Button Content="Save" 
     Command={Binding ElementName=UserAccountStatusGroupBox, Path=DataContext} /> 

當視圖加載時,按鈕調用CanExecute。如果返回值爲false,則該按鈕將被自動禁用。如果它是真的,它被啓用。當您的視圖模型中的屬性發生更改時,您將調用CanExecuteChanged處理程序,並且它將重新評估是否可以啓用保存按鈕。

通常,每個視圖/用戶控件應該有一個視圖模型。在這種情況下,您的視圖(Window/Page)應該將View Model作爲其數據上下文,而不是GroupBox。這是最佳做法。

我建議你read up on the Command Pattern MVVM可以攜手合作。對於這樣的事情,應該沒有任何代碼隱藏。它應該全部包含在視圖模型中。 View Model的目的是支持View。

+0

非常感謝。您所展示的內容對我來說更有意義,我肯定會更多地閱讀MVVM,並在本週末與您推薦的鏈接。 – famousKaneis

+0

這是一個好主意,閱讀模式,然後探索一些可用於WPF的各種實現。 MVVMLight和Prism一樣是一個很好的實現(雖然Prism for WPF對於非企業/模塊化應用程序有點過分殺手)。 WPF的默認MVVM實現有很多不足之處。 –

-1

通常我不會在我的頁面/窗口上設置控件的DataContext,而是設置根對象本身的數據上下文。我還添加了一個私有屬性,以便在必要時使用它(它只是返回值DataContext強制轉換爲我的視圖模型的類)。

然後你只需要使用這個屬性,那會給你訪問綁定到UI的值。

+0

我認爲你不需要從你的代碼隱藏中訪問你的視圖模型。應該使用代碼隱藏來操縱View的呈現方式,將數據提取到XAML中的綁定。我需要在代碼隱藏中放置視圖模型相關代碼的唯一原因是通過在非DI應用程序中通過構造函數傳入的依賴實例化它。理想情況下,您應該從XAML元素值本身('var name = this.lblName.Text')中獲取代碼中所需的數據,爲您提供虛擬機和代碼隱藏的抽象層。 –

1

一般而言,每個視圖你箱應該有一個視圖模型:

<Page.DataContext> 
    <local:MyViewModel/> 
</Page.DataContext> 

UserAccountsStatusHandler可能是在這種情況下,您的視圖模型。但是通過將它設置爲Page級別作爲DataContext,您不必擔心從後面的代碼挖掘UI的過程。

你可以只公開一個屬性在您的代碼隱藏這樣的:

private MyViewModel ViewModel 
{ 
    get 
    { 
     return DataContext as MyViewModel; 
    } 
} 

現在你可以使用:

MyViewModel.IsSaveEnabled = false; 

哪個更好。

但是,我會避免在代碼隱藏中放置太多的邏輯。我寧願讓你的按鈕在ViewModel上調用Save()方法,然後讓ViewModel相應地自行更新。

相關問題