やりたいこと
以前の記事で、View(コードビハインド)でしかできないことがあるので、コードビハインドに書いたメソッドを、ViewModelから呼ぶ、ということを実験した。
ViewModelのタイミングで(例えば、ボタンを押したときにプロパティの値をif分で判定して、条件を満たすときだけ)Viewのメソッドを呼ぶ、とかだと以前の記事のやり方をしないといけなさそうだが、だた単純に**「ボタンを押されたときにViewのメソッドを呼びたい」**という場合なら、もっと簡易的に簡単にできる方法を思いついたので備忘メモする。
やり方
下記を使う。
- Interaction.Triggers
- EventTrigger
- CallMethodAction
やることとしては、
- Interaction.TriggersとEventTriggerで何をトリガーにするか決めて
- CallMethodActionでコードビハインドに書いたメソッドを呼ぶ
だけ。
サンプルコード
<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:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
xmlns:local="clr-namespace:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800"
Name="Root">
<Grid>
<TextBlock Margin="40" Background="Yellow">この黄色いTextBlockを押すと、トリガーが発火します
<i:Interaction.Triggers>
<i:EventTrigger EventName="MouseDown">
<!-- ViewModelのメソッドの呼び方1 -->
<i:InvokeCommandAction Command="{Binding func}"/>
<!-- ViewModelのメソッドの呼び方2(ViewModelの中のメソッドを呼ぶ) -->
<ei:CallMethodAction TargetObject="{Binding}" MethodName="EventFunc"/>
<!-- ViewModelのメソッドの呼び方3(コードビハインドの中のメソッドを呼ぶ) -->
<ei:CallMethodAction TargetObject="{Binding ElementName=Root}" MethodName="CodeBehindFunc"/>
</i:EventTrigger>
</i:Interaction.Triggers>
</TextBlock>
</Grid>
</Window>
using System.Windows;
namespace WpfApp1
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new ViewModel();
}
public void CodeBehindFunc()
{
MessageBox.Show("CallMethodAction でトリガー発火(コードビハインドのメソッド)");
}
}
}
using System.Windows;
using System.Windows.Input;
namespace WpfApp1
{
class ViewModel
{
public ICommand func { get; set; }
public ViewModel()
{
func = new DelegateCommand(
() =>
{
MessageBox.Show("トリガー発火");
return;
});
}
public void EventFunc()
{
MessageBox.Show("CallMethodAction でトリガー発火(ViewModelのメソッド)");
}
}
}
説明
今回やりたかったのが、MainWindow.xamlの中の「ViewModelのメソッドの呼び方3(コードビハインドの中のメソッドを呼ぶ)」のところ。
<i:EventTrigger EventName="MouseDown">
で、TextBlockでマウスが押されたときに、コードビハインドに書かれたメソッド「CodeBehindFunc」を呼んでいる。
この書き方であれば、「EventTrigger」で表現できるイベントであれば、「ViewModelのICommand」「ViewModelクラスのメソッド」「コードビハインドのメソッド」のどれでも呼べる。
EventTriggerのEventNameを変えてやれば、クリックしたときだけでなく、表示時に一回なにかする、とかもできる。
また、サンプルのように、<i:EventTrigger EventName="MouseDown">
の中に書いたTriggerActionを継承したクラスのオブジェクト(CallMethodActionやInvokeCommandActionなど)をセットしてやれば、上から順番に実行してくれるので、ViewModelのICommandとコードビハインドのメソッドの両方を実行するとかもできそう。(それが良いかどうかは別問題)
備考
書き終わってから、「コントロールのイベントハンドラを追加して、そこに処理を書けばこんなことしなくて済むのでは?」と思ってしまった。
もしかすると、i:EventTrigger
よりも、PropertyChangedEventTrigger
を使って、ViewModelのプロパティが変わった時に、コードビハインドのメソッドを呼べる、とかの方が、真価なのかもしれない。
コード
関連記事
[C#/WPF]ビューモデルからビューのメソッドを呼ぶ
https://qiita.com/tera1707/items/158db72db21b17a1d9c5
【C#/WPF】EventTriggerを使って、Buttonでなくてもクリック時のCommandをかけるようにする
https://qiita.com/tera1707/items/7ecde6e97a19437cbf72
参考
WPF4.5入門 その58「Behavior」
https://blog.okazuki.jp/entry/2014/12/21/205558