WPFでINotifyPropertyChangedを使ってみたことがありました。
その後にもっと便利なReactiveProperyを知ったため、長らく忘れていました。
C#でWPF学習中「INotifyPropertyChanged」
.NET SDK(dotnet.exe)をインストールしたのでWPFを初めてみました。 Visual Studio 2019などのIDEでないと厳しいかとも思いますが、dotnet.exeとVisual Studio Codeで少しずつ学習...
その後にもっと便利なReactiveProperyを知ったため、長らく忘れていました。
正直MVVMなWPFは小規模なプログラミングだと面倒を感じ、WinFormのアプリケーションを作成していたところ、アプリケーションが肥大化するにつれてMVVMのような構造が欲しくなってきました。
WinFormのコントロールにもDataBindingsプロパティがあり、これに自前で作成したViewModelとバインディングできると便利かと思い調べたところ、WPFで使ったINotifyPropertyChangedから派生させたViewModelクラスのオブジェクトをデータソースとしてバインディングすることが出来るようです。
ソースコード
ファイル名:Form1.Designer.cs
namespace Form1VMSample1;
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Text = "Form1";
}
TextBox textBox1 = new()
{
Location = new Point(10, 10),
Size = new Size(500, 60),
Text = "textBox1", // 初期値
};
Label label1 = new()
{
Location = new Point(10, 70),
Size = new Size(500, 60),
Text = "label1", // 初期値
};
Button button1 = new()
{
Location = new Point(10, 140),
Size = new Size(500, 60),
Text = "button1", // 初期値
};
#endregion
}
ファイル名:Form1.cs
namespace Form1VMSample1;
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
var viewModel = new Form1ViewModel();
textBox1.DataBindings.Add(new Binding("Text", viewModel, "MyName"));
label1.DataBindings.Add(new Binding("Text", viewModel, "MyName"));
this.Load += (sender, e) =>
{
Controls.AddRange([textBox1, label1, button1]);
};
}
}
ファイル名:Form1ViewModel.cs
using System.ComponentModel;
using System.Diagnostics;
namespace Form1VMSample1;
class Form1ViewModel : INotifyPropertyChanged
{
public Form1ViewModel()
{
PropertyChanged += (o, e) =>
{
if (e.PropertyName == "MyName")
{
Debug.Print($"{_myName}"); // <= 変更後の値になっている
}
};
}
public event PropertyChangedEventHandler? PropertyChanged;
protected virtual void OnPropertyChanged(string name)
{
if (PropertyChanged is not null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
private string _myName = "Default";
public string MyName
{
get
{
return _myName;
}
set
{
if (_myName == value) return;
_myName = value;
OnPropertyChanged("MyName");
}
}
}
実行
起動してみると、textBox1とlabel1値がコンストラクタセットした初期値とは異なり、ViewModelのMyNameプロパティの初期値の”Default”に置き換えられていることが確認できます。
ViewModel⇒Viewがバインディングしていることが確認できたので、次にtextBox1の値を”Default”から”AAA”へ変更してみます。
lavel1の値も連動して”AAA”に変化しています。これはtextBox1とlabel1のTextプロパティを同じviewModel.MyNameとバインディングしているため連動したのだと思われます。
値を変更した際Form1ViewModelのPropertyChangedが呼び出され、_myNameの値がtextBox1で入力した値に変更されたことが出来ました。
コメント