[WPF] WPF画面とやり取りするための最低限の構成(.NET6版)

もくじ

https://tera1707.com/entry/2022/02/06/144447

# やりたいこと

.NET6でWPFでアプリを作るときにひな型になるものを作っておきたい。

# ついでにやりたいこと

例えばComboBoxの選択項目が変わったときのイベントをMVVMで書くためによく使っていた`EventTrigger`を使うときの準備が.NET Framework4.8のときと.NET6でちょっと変わったようなので、それの差し替えもやりたい。

そのやり方はこちらの記事参照。

https://qiita.com/nqdior/items/c9634f5c753cf4e53d4d

ざっくり言うとやることは下記。この辺を変える。

- nugetで `Microsoft.Xaml.Behaviors.Wpf`を入れる  
  (.NETfwでは「System.Windows.Interactivity」のアセンブリへの参照を追加していた)
- xamlの頭に「xmlns:i="http://schemas.microsoft.com/xaml/behaviors"」を入れる  
  (.NETfwでは「http://schemas.microsoft.com/expression/2010/interactivity」だった)

# ひな型コード

上にも書いたが、nugetでプロジェクトに `Microsoft.Xaml.Behaviors.Wpf`の追加必要。

``` MainWindow.cs
<Window x:Class="EventTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:EventTest"
        xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <StackPanel>
        <ComboBox ItemsSource="{Binding MyComboItemList}" SelectedIndex="{Binding MySelectedIndex}" Height="25">
            <!-- .NET6でi:Interaction.Triggers を使うには、 -->
            <!-- ①nugetで Microsoft.Xaml.Behaviors.Wpf を入れる -->
            <!-- ②xamlの頭に「xmlns:i="http://schemas.microsoft.com/xaml/behaviors"」を入れる -->
            <i:Interaction.Triggers>
                <i:EventTrigger EventName="SelectionChanged">
                    <!-- Eventには、LoadedやSelectionChangedが使える。 -->
                    <i:InvokeCommandAction Command="{Binding MySelectionChangedCommand}" />
                </i:EventTrigger>
            </i:Interaction.Triggers>
        </ComboBox>
        
        <Button Content="ボタン" Command="{Binding MyButtonChangedCommand}">
            
        </Button>
    </StackPanel>
</Window>
```

``` MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace EventTest
{
    public partial class MainWindow : Window, INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler? PropertyChanged;
        protected void OnPropertyChanged(string propertyName)
            => this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        // ----------------------------------------------------

        // コンボの選択中の項目のindex
        public int MySelectedIndex { get; set; }

        // コンボボックスの選択変更イベント
        public DelegateCommand MySelectionChangedCommand { get; set; }
        // ボタン押下イベント
        public DelegateCommand MyButtonChangedCommand { get; set; }

        private List<string> _myComboItemList = new List<string>() { "aaa", "bbb", "ccc" };
        public List<string> MyComboItemList
        {
            get { return _myComboItemList; }
            set { _myComboItemList = value; OnPropertyChanged(nameof(MyComboItemList)); }
        }

        public MainWindow()
        {
            InitializeComponent();

            DataContext = this;

            MySelectionChangedCommand = new DelegateCommand(() =>
            {
                Debug.WriteLine("選択した項目のindexは {0} です", MySelectedIndex);
            });

            MyButtonChangedCommand = new DelegateCommand(() =>
            {
                Debug.WriteLine("ボタンを押しました");
            });
        }
    }
}
```

``` DelegateCommand.cs
using System.Windows.Input;

namespace EventTest
{
    public class DelegateCommand : ICommand
    {
        System.Action execute;
        System.Func<bool> canExecute;

        public bool CanExecute(object parameter)
        {
            return true;
        }

        public event System.EventHandler CanExecuteChanged
        {
            add { CommandManager.RequerySuggested += value; }
            remove { CommandManager.RequerySuggested -= value; }
        }

        public void Execute(object? parameter)
        {
            execute();
        }

        public DelegateCommand(System.Action execute)
        {
            this.execute = execute;
        }

        public DelegateCommand(System.Action execute, System.Func<bool> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }
    }
}
```

※DelegateCommandは以前使っていたものをほぼそのまま使ってる。
　なんかnull許容がどうとかの警告？が出てるので、メンテ必要かも。