【C#】WPFのMVVMでEventTriggerを使用して各種イベントをバインドする
はじめに
前回の記事で WPF で MVVM をフレームワーク無しで構築してみました。
※こちらの記事はその続きになりますので良ければ参照ください。
構築したアプリケーションではボタンをクリックするとTextBox
の文字列が結合されるという処理でしたが、今のままではクリック時の処理を処理しか実装することができません。
そこで Microsoft が出しているBehaviorsというライブラリでEventTriggerを使用して
クリック以外の各種イベントに対して処理を実装しViewModel
へバインドするようアプリケーションを構築していこうと思います。
環境
- Windows10
- .NET6.0
- Visual Studio Community 2022
- WPF
Behaviors インストール
Behaviors を Nuget からインストールしていきます。
Nuget パッケージマネージャーで「Behaviors」と検索すると一番上に出てくるのでこちらをインストールします。
インストール完了後、Bihaviors
をView
で使用していきたいので参照を追加します。ここでは MainWindow.xaml 上部にxmlns:i="http://schemas.microsoft.com/xaml/behaviors"
を追加しました。
<Window x:Class="WpfApp1.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:WpfApp1"
xmlns:vm="clr-namespace:WpfApp1.ViewModel"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="490">
EventTrigger 実装
EventTrigger を使用する準備ができたので、各種イベントを実装していくのですが
今回は、
- Window ロード後に別 Window を開く
- ComboBox の選択を変更すると選択した値が TextBlock に表示される
の 2 点を実装したいと思います。
Window ロード後に別 Window を開く
ロード後に Command を実行するには以下のように記述します。
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding LoadedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
これでMainWindow
のLoaded
イベントに対してLoadedCommand
を実施するようになります。
LoadedCommand の実装内容は以下のような感じです。
using System;
using System.Windows.Input;
using WpfApp1.ViewModel;
namespace WpfApp1
{
public class LoadedCommand : ICommand
{
MainWindowViewModel m_vm;
public LoadedCommand(MainWindowViewModel vm)
{
m_vm = vm;
}
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// コマンドが利用可能かどうか
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public bool CanExecute(object? parameter)
{
return true;
}
/// <summary>
/// 実行時の処理
/// </summary>
/// <param name="parameter"></param>
/// <exception cref="NotImplementedException"></exception>
public void Execute(object? parameter)
{
var dlg = new LoadedWindow();
dlg.ShowDialog();
}
}
}
これをViewModel
でバインドすることでMainWindow
がロード後にExcute
が走り、別 Window が表示されるようになります。
ComboBox の選択を変更すると選択した値が表示される
こちらではまずMainWindow
のView
でComboBox
を以下のように作成します。
<ComboBox
HorizontalAlignment="Left"
VerticalAlignment="Top"
VerticalContentAlignment="Center"
Height="25"
Width="170"
Margin="150,400,0,0"
SelectedItem="{Binding SelectedItem}">
<ComboBoxItem Content="ぶどう" />
<ComboBoxItem Content="りんご" />
<ComboBoxItem Content="みかん" />
<ComboBoxItem Content="もも" />
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectionChangedCommand}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ComboBox>
ComboBox
の選択変更後に処理を走らせたいのでSelectionChanged
に対してEventTrigger
を設定します。
また、選択した値も取得する必要があるのでSelectedItem
をViewMode
へバインドしています。
SelectionChangedCommand の実装内容は以下のような感じです。
using System;
using System.Windows.Input;
using WpfApp1.ViewModel;
namespace WpfApp1
{
public class SelectionChangedCommand : ICommand
{
MainWindowViewModel m_vm;
public SelectionChangedCommand(MainWindowViewModel vm)
{
m_vm = vm;
}
public event EventHandler? CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
/// <summary>
/// コマンドが利用可能かどうか
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public bool CanExecute(object? parameter)
{
return m_vm.SelectedItem != null;
}
/// <summary>
/// 実行時の処理
/// </summary>
/// <param name="parameter"></param>
/// <exception cref="NotImplementedException"></exception>
public void Execute(object? parameter)
{
object content = m_vm.SelectedItem.Content;
if (content != null)
{
m_vm.ResultValue = content.ToString();
}
}
}
}
これでSelectedItem
の値をTextBlock
へ表示することができます。
実装後動作
画面ロード完了後
MainWindow
が起動すると自動的に別 Window が表示されました。
EventTrigger
でLoaded
イベントが走っていることが確認できます。
ComboBox 選択変更
はじめはComboBox
は何も選択されておらずTextBlock
も空白です。
ComboBox
で「ぶどう」を選択してみます。
TextBlock
に「ぶどう」が表示されたので次に「みかん」を選択してみます。
TextBlock
の値が「みかん」に変更されました。これでEventTrigger
でLoaded
イベントが走っていることが確認できました。
まとめ
今回は WPF の MVVM で各種イベントをEventTrigger
で処理する方法をお伝えしました。
ここまでできれば簡単なアプリケーションであれば実装できますが、高度なアプリケーションを MVVM でやろうとするとかなり難しいので、その時がフレームワークの使い時かもしれません。
次回以降、MVVM フレームワークも機会があれば紹介していきたいと思います。
参考資料
Discussion