2015-03-19 66 views
3

假設我們有一個模型(類別Model)具有以下屬性。如何在ViewModel更改後正確更新模型?

public string InputFileName 
{ 
    get { return m_InputFileName; } 
    set 
    { 
     m_InputFileName = value; 
     RaiseNotifyPropertyChanged("InputFileName"); 
    } 
} 

上述模型實現INotifyPropertyChanged接口,所以我們也有以下方法和以下的事件。下面的RaiseNotifyPropertyChanged方法用於更新ViewModel

#region INotifyPropertyChanged Implementation 

private void RaiseNotifyPropertyChanged(string property) 
{ 
    var handler = PropertyChanged; 
    if (handler != null) 
    { 
     handler(this, new PropertyChangedEventArgs(property)); 
    } 
} 

public event PropertyChangedEventHandler PropertyChanged; 

#endregion 

以下是實現視圖模型類的主要部分。

public class ViewModel : INotifyPropertyChanged 
{ 
    #region Members 

    private Model m_Model; 

    private string m_InputFileStr; 

    private readonly ICommand m_SubmitCommand; 

    #endregion 

    #region Constructors 

    public ViewModel() 
    { 
     m_Model = new Model(); 
     m_Model.PropertyChanged += new PropertyChangedEventHandler(this.Model_PropertyChanged); 

     m_InputFileStr = string.Empty; 

     // ... 
     // initialize m_SubmitCommand 
    } 

    #endregion 

    // ... 

    #region Properties 

    public string InputFileStr 
    { 
     get { return m_InputFileStr; } 
     set 
     { 
      if (value == m_InputFileStr) return; 
      m_InputFileStr = value; 
      OnPropertyChanged("InputFileStr"); 
      m_SubmitCommand.RaiseCanExecuteChanged(); 
     } 
    } 

    #endregion 

    #region INotifyPropertyChanged Implementation 

    public event PropertyChangedEventHandler PropertyChanged; 

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

    #endregion 

    // This method is called when the model changes, so the Model notified the ViewModel. 
    private void Model_PropertyChanged(object sender, PropertyChangedEventArgs args) 
    { 
     if (args.PropertyName == "InputFileName") 
     { 
      InputFileStr = m_Model.InputFileName; 
     } 
     else if (args.PropertyName == "OutputFileName") 
     { 
      OutputFileStr = m_Model.OutputFileName; 
     } 
     else if (args.PropertyName == "ReportText") 
     { 
      ReportTextStr = m_Model.ReportText; 
     } 
    } 
} 

以下是實現查看類的主要部分:

MainWindow.xaml

<TextBox Name="inputfileTextBox" 
     Text="{Binding Path=InputFileStr, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/> 

<Button Name="submitButton" 
     Content="Submit" 
     Command="{Binding SubmitCommand}"/> 

MainWindow.xaml.cs

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
     this.DataContext = new ViewModel(); 
    } 
} 

的以上實現工作正常:

  • View和ViewModel正確更新對方;
  • 模型正確更新ViewModel。

帶啓用視圖模型更新模型的目的,我想我會添加以下調用集合屬性視圖模型的InputFileStr內:

m_Model.InputFileName = value; 

然而,更新模型原因的這一解決方案一個明顯的意想不到的影響:

  1. 用戶修改視圖。
  2. ViewModel自動修改。
  3. ViewModel更新模型(m_Model.InputFileName = value;)。
  4. 模型更新...
  5. ...所以它會通知視圖模型有關的變化

是上述行爲正確的行爲?我期望如果ViewModel更新模型,那麼模型不必重新通知ViewModel有關相同的更改......作爲替代解決方案,我認爲我會爲模型添加一個Update方法:此方法應該更新該模型不使用模型屬性。

public void Update(string inputFileName) // this method does not notifies the ViewModel 
{ 
    m_InputFileName = inputFileName; 
} 

此替代解決方案是正確的解決方案還是有更好的解決方案?

回答

5

根據你的模型是什麼,你通常會調用一個「保存」方法或類似的。大多數模型(比如說一個數據庫)不需要/不需要實時對其進行實時更改。

所以在一般情況下,流動將是:

  1. 用戶調用「保存」操作
  2. 查看模型接收此作爲命令
  3. 查看模型調用「保存」操作上與所述模型新數據

如果您的DTO對象是在模型和視圖模型之間共享的,那麼您甚至不需要擔心同步。否則,這是同步它們的好時機。

在類似的說明中,使用PropertyChanged模型類通常是一個壞主意。對於初學者來說,它根本就沒有樂趣。相反,如果模型接收到新數據,請使用新數據向VM提供更多語義清晰的事件。

tldr;基本上,不要太擔心保持模型和視圖模型同步。很多時候,模型根本不會保留當前狀態的副本!即使是這樣,只要在視圖模型準備好「提交」更改時對其進行更新,並通過正常事件將視圖模型的外部更改通知給模型。

相關問題