WPF MVVM双向更新 [英] WPF MVVM two-way updates

查看:313
本文介绍了WPF MVVM双向更新的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用的这个例子

这是相关code片段:

These are the relevant code snippets:

XAML:

<Button Click="clkInit">Initialize</Button>
<Button Click="clkStudent">Add student</Button>
<Button Click="clkChangeStudent">Change students</Button>
(...)
<TabControl Name="tabControl1" ItemsSource="{Binding StudentViewModels}" >
   <TabControl.ItemTemplate>
      <DataTemplate>
         <TextBlock Text="{Binding Path=StudentFirstName}" />
      </DataTemplate>
   </TabControl.ItemTemplate>
   <TabControl.ContentTemplate>                
      <DataTemplate>
         <Grid>
            <Label Content="First Name" Name="label1" />
            <TextBox Name="textBoxFirstName" Text="{Binding Path=StudentFirstName}" />
            <Label Content="Last Name" Name="label2" />
            <TextBox Name="textBoxLastName" Text ="{Binding Path=StudentLastName}" />
         </Grid>                    
      </DataTemplate>
   </TabControl.ContentTemplate>
</TabControl>

主窗口:

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<StudentViewModel> _studentViewModels = 
        new ObservableCollection<StudentViewModel>();

   // Collection for WPF.
   public ObservableCollection<StudentViewModel> 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<Student> _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<Student>(() => 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的设置方法。我工作的这个项目是一个有点复杂,很多事情在类(这里的学生)本身。发生

If you read until here I already thank you :) Still, by calling "clkChangeStudent" I don't see the changes in the textbox. I guess it's because I don't call the set-method of the StudentViewModel. The project I'm working on is a bit complex and a lot of things happen in the class (here Student) itself.

我怎样才能获得通过设置值的文​​本框更新在学生类本身?

How can I get a textbox update by settings values in the Student-class itself?

推荐答案

您的实际code显然不会通知更改操作界面。原因很简单。你的方法,改变学生的名字是在学生模型和模型不实现INotifyPropertyChanged。

Your actual code clearly won't notify changes to the interface. The reason is simple. Your method that changes the student name is in the Student model and that model does not implement the INotifyPropertyChanged.

有2方案解决取决于一个问题这个问题,请问changeStudent()方法与对象模型来坚持,也就是说,能将你的要求,让您的changeStudent()方法在视模式?

There is 2 solutions to fix this issue depending on one question, does the changeStudent() method has to stick with the object model, that is to say, can your requirements allows you to move the changeStudent() method to the view model?

如果是的话,第一个解决方案,只需从模型中取出changeStudent方法,并将其移动到这样的视图模型:

If yes then, first solution, simply remove the changeStudent method from the model and move it to the view model like this:

class StudentViewModel : INotifyPropertyChanged
{
    ...

    public void changeStudent()
    {
        this.StudentLastName = "McDonald";
    }
}

在其他情况下,第二个解决方案,你必须引发事件每当模型属性的更改,然后让你的视图模型suscribe这些变化。您可以继续这样的模型:

In the other case, second solution, you have to raise events whenever a model property changes and then get your view model to suscribe to these changes. You can proceed like this in the model:

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

这两种解决方案会奏效。这实在是导入你明白,你的code 明确地需要通知接口每当价值的变化。

Both solution will work. It is really import that you understand that your code explicitely needs to notifies the interface whenever a value changes.

这篇关于WPF MVVM双向更新的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆