ビヘイビア・トリガーアクションの動き

#●ビヘイビア
ボタンをクリックしたときにメッセージを出すような、固定された特定のイベントに対する処理を記載する

#●ソース
ビヘイビアは自作することもできるため、自作のビヘイビアを作成して動作確認する。
下記ソースはテキストボックスに文字を入力する度に文字色を変更する。

###Rand_ForeColorクラス
自作BehaviorはBehavior<T>クラスを継承する。
型引数には用途に合った型を指定する。今回はテキストボックスに対する処理なのでTextBoxを指定。

OnAttachedメソッド、OnDetachingメソッドをオーバライドして処理を作成する。
　OnAttached：イベントを登録
　OnDetaching：イベントを解除

テキストボックスに入力された時を対象とするため、AssociatedObjectのPreviewTextInputイベントを指定している。
PreviewTextInputをKeyDownイベントに変更して、Key押下時に文字色を変更するなども可能。


```Rand_ForeColor.cs
/// <summary>
/// テキストボックスに入力される度に文字色を変更する
/// Behavior<T>を継承したクラス
/// </summary>
class Rand_ForeColor : Behavior<TextBox>
{
    /// <summary>
    /// イベントの登録
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();

        AssociatedObject.PreviewTextInput += OnPreviewTextInput;
    }

    /// <summary>
    /// イベントの解除
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();

        AssociatedObject.PreviewTextInput -= OnPreviewTextInput;
    }


    /// <summary>
    /// テキストボックス入力のイベント処理
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void OnPreviewTextInput(object sender, TextCompositionEventArgs e)
    {
        // 文字色の変更ができない場合イベントをキャンセルする
        e.Handled = !ChangeTextColor(sender);
    }

    /// <summary>
    /// テキストボックスの文字色をランダムに変更する
    /// </summary>
    /// <returns>変更成功／失敗</returns>
    private bool ChangeTextColor(object sender)
    {
        if (sender is TextBox textBox)
        {
            var rnd = new Random();
            var red = (byte)rnd.Next(256);
            var blue = (byte)rnd.Next(256);
            var green = (byte)rnd.Next(256);

            textBox.Foreground = new SolidColorBrush(Color.FromRgb(red, blue, green));

            return true;
        }

        return false;
    }
}
```

###MainWindowView.xmal
Interaction.Behaviorsで作成した自作のビヘイビアを指定する。

```MainWindowView.xmal
～省略～

<Grid >
    <StackPanel Orientation="Vertical" >
        <Label Content="Interaction.Behaviors" Margin="2"/>
        <TextBox Text="{Binding InputText}" Margin="3">
            <behaviors:Interaction.Behaviors>
                <v:Rand_ForeColor />
            </behaviors:Interaction.Behaviors>
        </TextBox>
    </StackPanel>
</Grid>
```


<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454547/d2d13cb9-1b3d-49bf-b7d3-ba9682c9fa82.png">　<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454547/d2789fb5-a03a-b75d-b3e8-caeffb4f7ce1.png">
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454547/a518828b-b438-9ce5-2ccd-34ee047c55c2.png">

***


#●トリガー・アクション
ビヘイビアで特定のイベント(きっかけとなるイベント)まで指定されているのに対し、トリガーは特定イベントに依存することなくイベント発火することができて、アクションで処理が実行される。

#●ソース
テキストボックスからフォーカスが外れる操作をトリガーとして(FirstName、LastName)、別のテキストボックス(FullName)に入力された内容をコピーするアクションを実装する。

###●MainWindowViewModelクラス
指定したトリガーにより実行されるアクションを記載する。
今回はCombineNameメソッドで、firstNameとlastNameを結合して、FullNameテキストボックスに表示する処理を実装する。

```MainWindowViewModel.cs
public class MainWindowViewModel : ViewModel
{
    // フルネーム
    private string fullName;
    public string FullName { get => fullName; set => RaisePropertyChangedIfSet(ref fullName, value); }

    // ファーストネーム
    private string firstName;
    public string FirstName { get => firstName; set => RaisePropertyChangedIfSet(ref firstName, value); }

    // ラストネーム
    private string lastName;
    public string LastName { get => lastName; set => RaisePropertyChangedIfSet(ref lastName, value); }


    /// <summary>
    /// firstName/lastNameの結合実行コマンド
    /// </summary>
    private ViewModelCommand combineNameCommand;
    public ViewModelCommand CombineNameCommand => combineNameCommand ??= new ViewModelCommand(CombineName);
    private void CombineName()
    {
        fullName = firstName + lastName;
        // 表示内容の更新
        RaisePropertyChanged(nameof(FullName));
    }

    // Some useful code snippets for ViewModel are defined as l*(llcom, llcomn, lvcomm, lsprop, etc...).
    public void Initialize()
    {
    }
}
```

```MainWindow.xmal
<behaviors:Interaction.Triggers>
    <!--フォーカスが外れるのをトリガーにCombineNameCommandが実行される-->
    <behaviors:EventTrigger EventName="LostFocus">
        <behaviors:InvokeCommandAction Command="{Binding CombineNameCommand}"/>
    </behaviors:EventTrigger>
</behaviors:Interaction.Triggers>

<Grid >
    <StackPanel Orientation="Vertical">
        <Label Content="Interaction.Triggers" Margin="2"/>

        <DockPanel Margin="3">
            <Label Content="FirstName :" Margin="2" DockPanel.Dock="Left"/>
            <TextBox Text="{Binding FirstName}" DockPanel.Dock="Right"/>
        </DockPanel>

        <DockPanel Margin="3">
            <Label Content="LastName :" Margin="2" DockPanel.Dock="Left"/>
            <TextBox Text="{Binding LastName}" DockPanel.Dock="Right"/>
        </DockPanel>

        <DockPanel Margin="3">
            <Label Content="FullName : " Margin="2" DockPanel.Dock="Left"/>
            <TextBox Text="{Binding FullName}" IsEnabled="False" DockPanel.Dock="Right"/>
        </DockPanel>
    </StackPanel>
</Grid>
```

<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454547/b0fa6df5-9110-14ac-6a00-5e6a3e667105.png">　<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/454547/2236e085-8225-4612-1549-50a5722fb714.png">



#・環境
VisualStudio2019
.Net Core3.0
Livet v3.2.1



#・参照
[WPF4.5入門 その58「Behavior」かずきのBlog@hatena]
(https://blog.okazuki.jp/entry/2014/12/21/205558)

[WPF4.5入門 その59「Behaviorの自作」 かずきのBlog@hatena](https://blog.okazuki.jp/entry/2014/12/22/235048)