げんさん日記

プログラミングで気付いた事等を書きます。

ViewのイベントをViewModelのコマンドで受け取る

2021年05月21日 12時47分44秒 | WPF
Viewで発生するイベントをViewModelのコマンドで受け取れるようにします。

プロジェクトの参照にSystem.Windows.Interactivityを追加します。

WindowにInteractivityを追加します。
<Window
  xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
  >

WindowのContentRenderedをフックします。
<i:Interaction.Triggers>
 <i:EventTrigger EventName="ContentRendered">
  <i:InvokeCommandAction Command="{Binding LoadCommand}"/>
 </i:EventTrigger>
</i:Interaction.Triggers>

上記内容でViewのContentRenderedイベントをViewModelのLoadCommandコマンドで受け取れます。


ViewのコマンドをViewModelで受け取るCommandを作成する。

2021年05月21日 11時24分11秒 | WPF
Viewから発生したコマンドをViewModelで受け取れるようにします。

ICommandを継承したRelayCommandを作成します。
public sealed class RelayCommand : ICommand
{
}

実行するメソッドを保存するプロパティを定義します。
private Action ActionMethod { get; set; }

コンストラクタを定義します。
public RelayCommand(Action execute)
{
  this.ActionMethod = execute;
}

実行するか判断するメソッドを定義します。
public bool CanExecute(object parameter)
{
  // 全て実行する。
  return true;
}

実行するメソッドを定義します。
public void Execute(object parameter)
{
  this.ActionMethod();
}

ICommandの実行メソッドを定義します。
void ICommand.Execute(object parameter)
{
  this.Execute(parameter);
}

使用例
public sealed class MainViewModel : BaseViewModel
{
  // ロードコマンド
  public ICommand LoadCommand { get; private set; }

  // コンストラクタ
  public MainViewModel ()
  {
    // コマンドを作成する。
    this.LoadCommand = new RelayCommand(this.OnLoad);
  }

  //ロード
  public void OnLoad()
  {
  }
}


Viewとバインドするモデルのベースを作成する。

2021年05月20日 15時42分27秒 | WPF
Viewとバインドするモデルの共通処理をベースとして作成します。

クラスの名前をBaseBindableModelにしてBaseModelを継承します。
※BaseModelは記事『全モデルのベースを作成する。(IDisposable)』を参照
public abstract class BaseBindableModel : BaseModel
{
}

プロパティチェンジイベントを定義します。
public event PropertyChangedEventHandler PropertyChanged;

プロパティを保存するDictionaryを定義します。
private Dictionary PropertieItems { get; set; }

プロパティの変更通知メソッドを作成します。
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
  if (this.PropertyChanged != null)
  {
   this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
  }
}

GetメソッドとSetメソッドを作成します
※詳細は記事『ViewModelのバインディングプロパティを簡単に定義する。』を参考

使用例
Viewへの通知まで行ってくれます。
public Class TestBindableModel : BaseBindableModel
{
  public double Value
  {
   get { return base.Get<double>(); }
   set { base.Set(value); }
}

ViewModelのベースを作成する。

2021年05月20日 15時42分27秒 | WPF
基本的な処理ができるViewModelのベースを作成します。
ViewModel側でViewの表示及び終了が可能になります。

BaseBindableModelを継承してBaseViewModelの殻を作成します。
BaseBindableModelは別記事『Viewとバインドするモデルのベースを作成する。』を参照
public abstract class BaseViewModel : BaseBindableModel
{
}

ShowDialogメソッドを追加します。
別記事『ViewModelからViewを表示する』を参照

画面終了メソッドを追加します。
protected void CloseWindow()
{
  // ViewModelからViewを生成する
  public IVewResult ShowDialog(T viewModel)
  {
    // アクティブなWindowを取得します。
    var view = Application.Current.Windows.OfType<Window>().SingleOrDefault(w => w.IsActive);
    view.Close();
  }
}

使用例
public sealed class MainViewModel : BaseViewModel
{
  // サブ画面表示メソッド
  public void ShowSubWindow(string para)
  {
    // サブ画面のViewModelを作成する
    using (var vm = new SubViewModel(para))
    {
      // サブ画面ViewModelを元にViewを表示する
      var ret = base.ShowDialog(vm);
      // 自画面を終了する
      base.CloseWindow();
    }
  }
}
上記のメリットは画面表示後の処理をViewModelで連続して処理を行うことができます。

全モデルのベースを作成する。(IDisposable)

2021年05月20日 15時00分10秒 | C#
メモリのリークを最小限にする為、デストラクタを正しく定義し、「BaseModel」を作成して行きます。

クラスの名前をBaseModelにしてIDisposableを継承します。

解放済みを確認するフラグを用意します。
public abstract class BaseModel : IDisposable
{
  protected bool IsDisposed { get; set; }
}

次にデストラクタを定義しDisposeをfaiseで呼び出します。
~BaseModel()
{
  this.Dispose(false);
}

PublicのDisposeを定義します。
public void Dispose()
{
  // DisposeをTrueで呼び出す。
  this.Dispose(true);
  // 自分を解放する。
  GC.SuppressFinalize(this);
}

管理外のオブジェクトを解放する為、ProtectedのDisposeを定義します。
protected virtual void Dispose(bool disposing = true)
{
  // 解放済みなら何もしない
  if (this.IsDisposed == true) return;

  // 管理外のオブジェクトを解放する。
  if (disposing == true)
  {
  }
  this.IsDisposed = true;
}

継承先のモデル例
public Class TestModel : BaseModel
{
  // Disposeをオーバーライド
  protected override void Dispose(bool disposing = true)
  {
   // 解放済みなら何もしない
   if (this.IsDisposed == true) return;

   // 管理外オブジェクトの解放
   if (disposing == true)
   {
    // 自クラスのオブジェクト&イベントの解放
   }

   // ベースの解放を呼び出す。
   base.Dispose(disposing);
  }
}