C#のWinFormsでINotifyPropertyChangedを使ってコントロールとデータバインディングしてみる。2

C# コンピュータ
C#

前回はテキストボックスとラベルに同じプロパティをバインドしましたが、今回は別のオブジェクトをバインドし、変更通知で連動させてみます。

ソースコード

ファイル名:Form1.Designer.cs

namespace VMsample01;

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
}

ファイル名:Form1ViewModel.cs

using System.ComponentModel;
using System.Diagnostics;

namespace VMsample01;
class Form1ViewModel : INotifyPropertyChanged
{
    public Form1ViewModel()
    {
        PropertyChanged += (o, e) =>
        {
            if (e.PropertyName == "MyName")
            {
                Debug.Print("0");
                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");
        }
    }
    private string _dispName = "Default";

    public string DispName
    {
        get
        {
            return _dispName;
        }
        set
        {
            if (_dispName == value) return;
            _dispName = value;
            OnPropertyChanged("DispName");
        }
    }

}

ファイル名:Form1.cs

using System.Diagnostics;

namespace VMsample01;

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, "DispName"));

        this.Load += (sender, e) =>
        {
            Controls.AddRange([textBox1, label1, button1]);
        };

        viewModel.PropertyChanged += (sender, e) =>
        {
            // MyName意外は処理しない
            if (e.PropertyName != "MyName") return;
            if (sender is null) return;

            Debug.Print("1");
            var vm = (Form1ViewModel)sender;

            // ここで連動
            vm.DispName = vm.MyName;
            
        };
    }
}

テキストボックスの文字を変更してボタンを押すとラベルの文字が変わる振る舞いは前回の記事と同じです。

今回はラベルの表示文字列用にDispNameという名前のプロパティを用意しバインドしました。

テキストボックスは前回と同じくMyNameというプロパティとバインドしており、テキストボックスの値を変更すると、MyNameプロパティの値が変更され、変更の通知がPropertyChangedで処理され、その中でDispNameへMyNameの値を代入することで連動させています。

コメント