XAMLを使わないWPF入門03「ICommandによるコマンドバインディング」

コンピュータ

XAMLを使わないWPFでプロパティとのバインドを前回試しました。今回はICommandのオブジェクトとのバインドを試してみたいと思います。

サンプルコード

・プロジェクトの作成

dotnet new wpf -f net8.0 -n NoXAML03
cd NoXAML03
rm *.xaml
rm MainWindow.xaml.cs

ファイル名:NoXAML03.csproj

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net8.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <ImplicitUsings>enable</ImplicitUsings>
    <UseWPF>true</UseWPF>
    <StartupObject>NoXAML03.App</StartupObject>
  </PropertyGroup>

</Project>

ファイル名:RelayCommand.cs

using System.Windows.Input;

namespace NoXAML03;
public class RelayCommand : ICommand
{
    private readonly Action<object?> _execute;
    private readonly Func<object?, bool>? _canExecute;

    public RelayCommand(Action<object?> execute, Func<object?, bool>? canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object? parameter) => _canExecute?.Invoke(parameter) ?? true;

    public void Execute(object? parameter) => _execute(parameter);

    public event EventHandler? CanExecuteChanged;
    public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}

ICommandの実装

ファイル名:MainWindowViewModel.cs

using System.Windows;
using System.Windows.Input;

namespace NoXAML03;

public class MainWindowViewModel
{
    public ICommand ClickCommand { get; }

    public MainWindowViewModel()
    {
        ClickCommand = new RelayCommand(_ =>
        {
            MessageBox.Show("ボタンがクリックされました!");
        });
    }
}

コマンドを実行するViewModel

ファイル名:App.xaml.cs

using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;

namespace NoXAML03;

public class App : Application
{
    // エントリポイント
    [STAThread]
    public static void Main()
    {
        var app = new App();
        app.Startup += (sender, e) =>
        {
            var viewModel = new MainWindowViewModel();

            // UIの構築
            var button = new Button
            {
                Content = "クリックして実行",
                Width = 150,
                Height = 50,
                Margin = new Thickness(20)
            };

            // コマンドバインディング
            // Binding:CommandプロパティにViewModelのClickCommandをバインド
            var binding = new Binding("ClickCommand");
            BindingOperations.SetBinding(button, Button.CommandProperty, binding);

            // レイアウト
            var stackPanel = new StackPanel
            {
                Children = { button },
                VerticalAlignment = VerticalAlignment.Center,
                HorizontalAlignment = HorizontalAlignment.Center
            };

            // ウィンドウの構築と表示
            var window = new Window
            {
                Title = "ICommandオブジェクトとバインド",
                Width = 300,
                Height = 150,
                DataContext = viewModel,
                Content = stackPanel,
            };

            window.Show();

        };
        app.Run();
    }}

エントリポイント

実行イメージ

1.ボタンをクリック

2.メッセージボックスが表示されます。

解説

ButtonのCommandプロパティとViewModelで定義したClickCommandをバインドは以下の部分で処理をしています。

 // Binding:CommandプロパティにViewModelのClickCommandをバインド
var binding = new Binding("ClickCommand");
BindingOperations.SetBinding(button, Button.CommandProperty, binding);
public static void BindingOperations.SetBinding(DependencyObject target, DependencyProperty dp, BindingBase binding);

バインディングオブジェクトは生成したButtonオブジェクト

var button = new Button

ターゲットオブジェクトはButtonオブジェクトのCommandProperty

Button.CommandProperty

バインディングオブジェクトはビューモデルの

public ICommand ClickCommand { get; }

からバインディングオブジェクトを生成

var binding = new Binding("ClickCommand");

最後に

コマンドの場合、流れがView→ViewModelの一方通行のおかげか、双方向のプロパティのバインドよりシンプルな感じがします。

コメント