最近あまり面白い話題が少ない感じでしたがついに来ました。みんな大好き Windows フォームアプリのお話です。
↑ のブログ記事。見ていきましょう!
※ 現在 WPF でなく WinForms を愛用している日本の IT 技術者が WinForms アプリを MVVM で作りたいと思っているかは別として。
■ OnRequestCommandExecute メソッド
ButtonBase クラスと ToolStripItem クラスに OnRequestCommandExecute メソッドが追加されたとのことです。
ButtonBase クラス、確かに、バージョン 7 からとなっています。
learn.microsoft.com
ToolStrigItem クラスには見当たりません......。
learn.microsoft.com
しかし Visual Studio で見ると確かにいますね。
このメソッドを override することで、Command の呼び出しを制御できるようですね。 試してみましょう。
■ 検証コード
public class BindableBase : System.ComponentModel.INotifyPropertyChanged { public event System.ComponentModel.PropertyChangedEventHandler? PropertyChanged; protected bool SetProperty<T>(ref T property, T value, [System.Runtime.CompilerServices.CallerMemberName] string propertyName = "") { if (Object.Equals(property, value)) return false; property = value; PropertyChanged?.Invoke(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); return true; } } class Command : System.Windows.Input.ICommand { public event EventHandler? CanExecuteChanged; private readonly Action<object?> _commandAction; private readonly Func<bool>? _canExecuteCommandAction; public Command(Action<object?> commandAction, Func<bool>? canExecuteCommandAction = null) { _commandAction = commandAction; _canExecuteCommandAction = canExecuteCommandAction; } public bool CanExecute(object? parameter) => _canExecuteCommandAction?.Invoke() ?? true; public void Execute(object? parameter) => _commandAction.Invoke(parameter); public void NotifyCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); } public class ViewModel : BindableBase { bool _enabled = true; private string _text; public string Text { get => _text; private set => SetProperty(ref _text, value); } public System.Windows.Input.ICommand ButtonCommand { get; init; } public ViewModel() { ButtonCommand = new Command(((parameter) => Text += $"Button clicked: {parameter?.ToString()}\n"), canExecute); bool canExecute() => _enabled; } }
namespace WinFormsApp1 { public partial class Form1 : Form { class MyButton : System.Windows.Forms.Button { public bool CanRequestExecute { get; set; } = true; protected override void OnRequestCommandExecute(EventArgs e) { if (CanRequestExecute) base.OnRequestCommandExecute(e); } } public Form1() { this.components = new System.ComponentModel.Container(); InitializeComponent(); var viewModel = new ViewModel(); var bindingSource = new System.Windows.Forms.BindingSource(components); bindingSource.DataSource = viewModel; var button = new MyButton { AutoSize = true, Location = new System.Drawing.Point(16, 32), Size = new System.Drawing.Size(94, 29), Text = "button1", UseVisualStyleBackColor = true, }; var checkBox = new System.Windows.Forms.CheckBox { AutoSize = true, Location = new System.Drawing.Point(16, 76), Size = new System.Drawing.Size(101, 24), Text = "checkBox1", UseVisualStyleBackColor = true, Checked = true, }; var label = new System.Windows.Forms.Label { AutoSize = true, Location = new System.Drawing.Point(20, 172), Size = new System.Drawing.Size(50, 20), Text = "label1", }; button.DataBindings.Add(new System.Windows.Forms.Binding("Command", bindingSource, "ButtonCommand", true)); label.DataBindings.Add(new System.Windows.Forms.Binding("Text", bindingSource, "Text", true)); this.Controls.Add(button); this.Controls.Add(checkBox); this.Controls.Add(label); checkBox.CheckedChanged += (object? sender, EventArgs e) => button.CanRequestExecute = ((CheckBox?)sender)?.Checked ?? true; } } }
実行結果
計算通り! CheckBox の ON/OFF を切り替えるとボタンの Command が実行されたりされなかったりします。画像ではわからないですけど。
■ コードの要点
ボタンの派生クラスを作って OnRequestCommandExecute メソッドを override しています。
class MyButton : System.Windows.Forms.Button { public bool CanRequestExecute { get; set; } = true; protected override void OnRequestCommandExecute(EventArgs e) { if (CanRequestExecute) base.OnRequestCommandExecute(e); } }
次回
次回は DataContext プロパティを見ていきましょう。