2015-03-19 67 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;基本上,不要太担心保持模型和视图模型同步。很多时候,模型根本不会保留当前状态的副本!即使是这样,只要在视图模型准备好“提交”更改时对其进行更新,并通过正常事件将视图模型的外部更改通知给模型。

相关问题