WPF MVVM双向更新

我正在尝试使用此示例设置工作双向更新。

这些是相关的代码片段:

XAML:

   (...)           

主窗口:

 public partial class MainWindow : Window { internal MainWindowViewModel myMWVM; public MainWindow() { InitializeComponent(); } private void clkInit(object sender, RoutedEventArgs e) { myMWVM= new MainWindowViewModel(); DataContext = myMWVM; } private void clkStudent(object sender, RoutedEventArgs e) { myMWVM.StudentViewModels.Add(new StudentViewModel()); } // For testing - call a function out of the student class to make changes there private void clkChangeStudent(object sender, RoutedEventArgs e) { for (Int32 i = 0; i < test.StudentViewModels.Count; i++) { myMWVM.StudentViewModels.ElementAt((int)i).changeStudent(); } } } 

主要观点:

 class MainWindowViewModel : INotifyPropertyChanged { ObservableCollection _studentViewModels = new ObservableCollection(); // Collection for WPF. public ObservableCollection StudentViewModels { get { return _studentViewModels; } } // Constructor. Add two stude public MainWindowViewModel() { _studentViewModels.Add(new StudentViewModel()); _studentViewModels.Add(new StudentViewModel()); } // Property change. public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } 

学生观点:

 class StudentViewModel : INotifyPropertyChanged { Lazy _model; string _studentFirstName; public string StudentFirstName { get { return _studentFirstName; } set { if (_studentFirstName != value) { _studentFirstName = value; _model.Value.StudentFirstName = value; OnPropertyChanged("StudentFirstName"); } } } string _studentLastName; public string StudentLastName { get { return _studentLastName; } set { if (_studentLastName != value) { _studentLastName = value; _model.Value.StudentLastName = value; OnPropertyChanged("StudentLastName"); } } } public void changeStudent() { _model.Value.changeStudent(); } public StudentViewModel() { _studentFirstName = "Default"; _model = new Lazy(() => new Student()); } public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } 

学生:

 class Student { public string StudentFirstName { get; set; } public string StudentLastName { get; set; } public Student() { MessageBox.Show("Student constructor called"); } public Student(string nm) { StudentLastName = nm; } public void changeStudent() { StudentLastName = "McDonald"; } } 

如果你读到这里我已经感谢了你:)仍然,通过调用“clkChangeStudent”我没有看到文本框中的更改。 我想这是因为我没有调用StudentViewModel的set方法。 我正在研究的项目有点复杂,很多事情都发生在class级(这里是学生)本身。

如何通过Student-class本身的设置值获取文本框更新?

您的实际代码显然不会通知接口的更改。 原因很简单。 更改学生姓名的方法在Student模型中,该模型未实现INotifyPropertyChanged。

根据一个问题,有两个解决方案来解决这个问题,changeStudent()方法是否必须坚持使用对象模型,也就是说,您的需求是否允许您将changeStudent()方法移动到视图模型?

如果是,那么, 首先解决方案 ,只需从模型中删除changeStudent方法并将其移动到视图模型,如下所示:

 class StudentViewModel : INotifyPropertyChanged { ... public void changeStudent() { this.StudentLastName = "McDonald"; } } 

在另一种情况下, 第二个解决方案 ,您必须在模型属性更改时引发事件,然后让您的视图模型inheritance这些更改。 你可以在模型中这样继续:

 class Student : INotifyPropertyChanged { ... private string studentLastName; public string StudentLastName { get { return this.studentLastName; } set { if(this.studentLastname != value) { this.studentLastName = value; this.OnPropertyChanged("StudentLastName"); } } } } 

对于视图模型:

 class StudentViewModel : INotifyPropertyChanged { ... public StudentViewModel(Student model) { this._model = model; this._model.PropertyChanged += (sender, e) => { if(e.PropertyName == "StudentLastName") { this.OnPropertyChanged("StudentLastName"); } }; } } 

两种解决方案都有效。 您理解,只要值发生变化,您的代码明确需要通知接口,这非常重要。

ChangeStudent不会调用在视图模型中触发属性notify事件的任何方法,而是改变底层模型。 正是这些事件触发了视图自我更新。

另外,您还应该从视图中查看命令绑定,而不是在代码隐藏中使用单击处理程序。 这样你的视图就不需要了解附加的视图模型,也可以是纯粹的表示。

首先,您应该使用命令而不是事件。

在您当前的结构中,您必须添加一个

 OnPropertyChanged("StudentLastName"); 

在StudentViewModel中调用您的ChangedStudent()方法。 之后,您必须将Bindings的UpdateSourceTrigger设置为PropertyChanged

 Text="{Binding Path=StudentFirstName, UpdateSourceTrigger=PropertyChanged}"