C# > Visual Studio 2017 でLivetを試してみた

# 概要
Livet初学者です。Visual Studio 2017にLivetを入れてMVVMの形でHelloWorldを書いてみました。
これでいいのか全く自信がありません。
# コード
```MainWindow.xaml
<Window x:Class="LivetHelloApplication.Views.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
        xmlns:l="http://schemas.livet-mvvm.net/2011/wpf"
        xmlns:v="clr-namespace:LivetHelloApplication.Views"
        xmlns:vm="clr-namespace:LivetHelloApplication.ViewModels"
        Title="Livetサンプル：挨拶" Height="350" Width="525">

    <Window.DataContext>
        <vm:MainWindowViewModel/>
    </Window.DataContext>

    <i:Interaction.Triggers>

        <!--Viewに特別な要件が存在しない限りは、トリガーやアクションの自作にこだわらず積極的にコードビハインドを使いましょう -->
        <!--Viewのコードビハインドは、基本的にView内で完結するロジックとViewModelからのイベントの受信(専用リスナを使用する)に限るとトラブルが少なくなります -->
        <!--Livet1.1からはコードビハインドでViewModelのイベントを受信するためのWeakEventLisnterサポートが追加されています -->

        <!--WindowのContentRenderedイベントのタイミングでViewModelのInitializeメソッドが呼ばれます-->
        <i:EventTrigger EventName="ContentRendered">
            <l:LivetCallMethodAction MethodTarget="{Binding}" MethodName="Initialize"/>
        </i:EventTrigger>

        <!--Windowが閉じたタイミングでViewModelのDisposeメソッドが呼ばれます-->
        <i:EventTrigger EventName="Closed">
            <l:DataContextDisposeAction/>
        </i:EventTrigger>

        <!--WindowのCloseキャンセル処理に対応する場合は、WindowCloseCancelBehaviorの使用を検討してください-->

    </i:Interaction.Triggers>

    <Grid FocusManager.FocusedElement="{Binding ElementName=textBox}">
        <TextBox x:Name="textBox" HorizontalAlignment="Left" Height="23" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Margin="10,10,0,0" Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"/>
        <Button x:Name="button" Content="こんにちは！" HorizontalAlignment="Left" VerticalAlignment="Top" Width="75" Margin="135,13,0,0" IsDefault="True" Command="{Binding OutputHelloMessageCommand, Mode=OneWay}"/>
        <TextBlock x:Name="textBlock" TextWrapping="Wrap" VerticalAlignment="Top" Margin="10,38,10,0" Text="{Binding HelloMessage}"/>
    </Grid>
</Window>
```
```MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;

using Livet;
using Livet.Commands;
using Livet.Messaging;
using Livet.Messaging.IO;
using Livet.EventListeners;
using Livet.Messaging.Windows;

using LivetHelloApplication.Models;

namespace LivetHelloApplication.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {
        /* コマンド、プロパティの定義にはそれぞれ 
         * 
         *  lvcom   : ViewModelCommand
         *  lvcomn  : ViewModelCommand(CanExecute無)
         *  llcom   : ListenerCommand(パラメータ有のコマンド)
         *  llcomn  : ListenerCommand(パラメータ有のコマンド・CanExecute無)
         *  lprop   : 変更通知プロパティ(.NET4.5ではlpropn)
         *  
         * を使用してください。
         * 
         * Modelが十分にリッチであるならコマンドにこだわる必要はありません。
         * View側のコードビハインドを使用しないMVVMパターンの実装を行う場合でも、ViewModelにメソッドを定義し、
         * LivetCallMethodActionなどから直接メソッドを呼び出してください。
         * 
         * ViewModelのコマンドを呼び出せるLivetのすべてのビヘイビア・トリガー・アクションは
         * 同様に直接ViewModelのメソッドを呼び出し可能です。
         */

        /* ViewModelからViewを操作したい場合は、View側のコードビハインド無で処理を行いたい場合は
         * Messengerプロパティからメッセージ(各種InteractionMessage)を発信する事を検討してください。
         */

        /* Modelからの変更通知などの各種イベントを受け取る場合は、PropertyChangedEventListenerや
         * CollectionChangedEventListenerを使うと便利です。各種ListenerはViewModelに定義されている
         * CompositeDisposableプロパティ(LivetCompositeDisposable型)に格納しておく事でイベント解放を容易に行えます。
         * 
         * ReactiveExtensionsなどを併用する場合は、ReactiveExtensionsのCompositeDisposableを
         * ViewModelのCompositeDisposableプロパティに格納しておくのを推奨します。
         * 
         * LivetのWindowテンプレートではViewのウィンドウが閉じる際にDataContextDisposeActionが動作するようになっており、
         * ViewModelのDisposeが呼ばれCompositeDisposableプロパティに格納されたすべてのIDisposable型のインスタンスが解放されます。
         * 
         * ViewModelを使いまわしたい時などは、ViewからDataContextDisposeActionを取り除くか、発動のタイミングをずらす事で対応可能です。
         */

        /* UIDispatcherを操作する場合は、DispatcherHelperのメソッドを操作してください。
         * UIDispatcher自体はApp.xaml.csでインスタンスを確保してあります。
         * 
         * LivetのViewModelではプロパティ変更通知(RaisePropertyChanged)やDispatcherCollectionを使ったコレクション変更通知は
         * 自動的にUIDispatcher上での通知に変換されます。変更通知に際してUIDispatcherを操作する必要はありません。
         */

        private Model model = new Model();
        private PropertyChangedEventListener listener;

        public void Initialize()
        {
            listener = new PropertyChangedEventListener(model);
            listener.RegisterHandler(HelloMessageChanged);
        }

        private void HelloMessageChanged(object sender, PropertyChangedEventArgs e)
        {
            switch (e.PropertyName)
            {
                case nameof(model.HelloMessage):
                    HelloMessage = model.HelloMessage;
                    break;
                case nameof(model.Name):
                    Name = model.Name;
                    break;
                default:
                    break;
            }
        }

        #region HelloMessage変更通知プロパティ
        private string _HelloMessage = string.Empty;

        public string HelloMessage
        {
            get
            { return _HelloMessage; }
            set
            { 
                if (_HelloMessage == value)
                    return;
                _HelloMessage = value;
                model.HelloMessage = _HelloMessage;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region Name変更通知プロパティ
        private string _Name = string.Empty;

        public string Name
        {
            get
            { return _Name; }
            set
            { 
                if (_Name == value)
                    return;
                _Name = value;
                model.Name = _Name;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region OutputHelloMessageCommand
        private ListenerCommand<string> _OutputHelloMessageHelloCommand;

        public ListenerCommand<string> OutputHelloMessageCommand
        {
            get
            {
                if (_OutputHelloMessageHelloCommand == null)
                {
                    _OutputHelloMessageHelloCommand = new ListenerCommand<string>(OutputHelloMessage);
                }
                return _OutputHelloMessageHelloCommand;
            }
        }

        public void OutputHelloMessage(string parameter)
        {
            model.Hello();
        }
        #endregion
    }
}
```
```Model.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Livet;

namespace LivetHelloApplication.Models
{
    public class Model : NotificationObject
    {
        #region HelloMessage変更通知プロパティ
        private string _HelloMessage = string.Empty;

        public string HelloMessage
        {
            get
            { return _HelloMessage; }
            set
            { 
                if (_HelloMessage == value)
                    return;
                _HelloMessage = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        #region Name変更通知プロパティ
        private string _Name = string.Empty;

        public string Name
        {
            get
            { return _Name; }
            set
            { 
                if (_Name == value)
                    return;
                _Name = value;
                RaisePropertyChanged();
            }
        }
        #endregion

        public void Hello()
        {
            HelloMessage = Name != "" ? $"{Name}さん、こんにちは！" : string.Empty;
        }
    }
}
```