😺

WindowsフォームでのDataBinding

2024/06/07に公開

はじめに

長年Windowsフォームで実装してましたが、コードでのDataBindingを行ったことも、ButtonのクリックイベントをBindingする事もなかったので、今更ながら実装してみました。

環境

VS2022
Windwos11 Pro(64bit)

プロジェクトの作成

新しいプロジェクトの作成で、「Windowsフォームアプリ」を選択
作成したプロジェクトにViewModelクラスを追加

コードで実装してみる

namespace WinFormsApp1
{
    internal class ViewModel : BindableBase
    {
        public string Text { 
            get => _text; 
            set => SetProperty(ref _text, value); 
        }
        string _text = "";
        public string Label { get => _label; set => SetProperty(ref _label, value); }
        string _label = "";
        public System.Windows.Input.ICommand ButtonCommand { get; init; }
        public ViewModel() {
            ButtonCommand = new Command(Apply);  
        }

        void Apply()
        {
            if (int.TryParse(Text, out var num))
            {
                Label = $"{num}";
            }
            else
            {
                Label = "整数の数値を入力してください";
            }
        }
       
    }
}

BindableBaseを使用したので、Nugetから「Prism.Core」を入れてください。
テキストボックスに入力した文字を、ボタンを押すことで、ラベルに反映する実装として、それらコントロールにBindするプロパティ達を実装します。

ボタンのクリックイベントをBindingするためにCommandクラスを実装します。プロジェクトに追加して、実装ください。
内容はほぼ定型文ですね。

namespace WinFormsApp1
{
    internal class Command : System.Windows.Input.ICommand
    {
        public event EventHandler? CanExecuteChanged;

        private readonly Action _commandAction;
        private readonly Func<bool>? _canExecuteCommandAction;

        public Command(Action commandAction, Func<bool>? canExecuteCommandAction = null)
        {
            _commandAction = commandAction;
            _canExecuteCommandAction = canExecuteCommandAction;
        }

        public bool CanExecute(object? parameter) => _canExecuteCommandAction?.Invoke() ?? true;
        public void Execute(object? parameter) => _commandAction.Invoke();
        public void NotifyCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

これは、丸まるコピーで使いまわしです。

次に、Formのコンストラクタで、Bindingの設定を行います。

namespace WinFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            this.DataContext = new System.Windows.Forms.BindingSource(this.components = new System.ComponentModel.Container())
            {
                DataSource = new ViewModel()
            };
            InitializeComponent();

            textBox1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.DataContext, "Text", true));
            label1.DataBindings.Add(new System.Windows.Forms.Binding("Text", this.DataContext, "Label", true));
            button1.DataBindings.Add(new System.Windows.Forms.Binding("Command", this.DataContext, "ButtonCommand",true));
        }
    }
}

別段難しいことはありません。3種のコントロール毎の設定を行っています。

Form1に配置するコントロールは以下の感じで置いてます。

デザイナ画面の設定で極力楽をする

Form1に配置するコントロールは、上記の通りで同じとしてください。
さすがにViewModelクラスは実装する必要があるので、クラスを追加して、コードを記述。なのでBindableBaseも使用するので、NegetからのPrism.Coreも必要です。
ボタン操作もあるので、Commandの実装も必要ですね。
ViewModel.csとCommand.csを追加してください。

それと、後でViewModelは外から見たいので、クラスをPublicとしておいて下さい。

namespace WinFormsApp2
{
-    internal class ViewModel : BindableBase
+    public class ViewModel : BindableBase
    {
        public string Text

Formのプロパティから、「DataBindings」を選択して「DataContext」を選択して、下矢印をクリック、「オブジェクトデータソースを追加します」をクリック下さい。

ViewModelが選択できるので、選択してOKを押す

ViewModelが表示されててないなら、一回ビルドしてみて下さい。
あとは、コントロール毎に使用するプロパティを設定していく。

コントロール プロパティ画面 選択項目
txtBox1 DataBindings/Text Text
label1 DataBindings/Text Label
button1 DataBindings/Command ButtonCommand

最後にForm1にちょっと、コードを追加

public Form1()
{
    InitializeComponent();
+    viewModelBindingSource.DataSource = new ViewModel();
}

Discussion