0

この例を使用して、動作する双方向アップデートをセットアップしようとしています。

関連するコードスニペットは次のとおりです。

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のset-methodを呼び出さなかったからだと思います。私が取り組んでいるプロジェクトは少し複雑で、クラス(ここでは学生)自体で多くのことが起こります。

Student-class自体の設定値によってテキストボックスを更新するにはどうすればよいですか?

4

3 に答える 3

5

実際のコードは明らかにインターフェースの変更を通知しません。理由は簡単です。学生名を変更するメソッドはStudentモデルにあり、そのモデルはINotifyPropertyChangedを実装していません。

1つの質問に応じて、この問題を修正する2つの解決策があります。changeStudent()メソッドはオブジェクトモデルに固執する必要がありますか?つまり、要件によってchangeStudent()メソッドをビューモデルに移動できますか?

はいの場合、最初の解決策は、モデルからchangeStudentメソッドを削除し、次のようにビューモデルに移動するだけです。

class StudentViewModel : INotifyPropertyChanged
{
    ...

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

もう1つの場合、2番目の解決策では、モデルプロパティが変更されるたびにイベントを発生させてから、ビューモデルにこれらの変更をサブスクライブさせる必要があります。モデルでは、次のように進めることができます。

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

どちらのソリューションも機能します。値が変更されるたびにコードがインターフェイスに明示的に通知する必要があることを理解することは非常に重要です。

于 2012-11-23T14:24:56.280 に答える
1

ChangeStudentは、ビューモデルでプロパティ通知イベントをトリガーするメソッドを呼び出さず、代わりに基になるモデルを変更します。ビューがそれ自体を更新するきっかけとなるのは、これらのイベントです。

余談ですが、コードビハインドでクリックハンドラーを使用する代わりに、ビューからコマンドバインディングを確認する必要もあります。そうすれば、ビューは、添付されているビューモデルについて何も知る必要がなく、純粋なプレゼンテーションにすることができます。

于 2012-11-23T13:43:51.357 に答える
0

まず、イベントの代わりにコマンドを使用する必要があります。

現在の構造では、を追加する必要があります

OnPropertyChanged("StudentLastName");

StudentViewModelのChangedStudent()メソッドを呼び出します。その後、BindingsのUpdateSourceTriggerをPropertyChangedに設定する必要があります

Text="{Binding Path=StudentFirstName, UpdateSourceTrigger=PropertyChanged}"
于 2012-11-23T13:53:07.603 に答える