概要
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;
}
}
}