Prism コードサンプル学習：12-UsingCompositeCommands

# Prism コードサンプル学習：12-UsingCompositeCommands

## はじめに

以下の記事の続きです。
<https://qiita.com/mngreen/items/95dd62ee8086887f5d0b>

## 12-UsingCompositeCommands

本サンプルでは、CompositeCommandsの実装方法を紹介しています。
Compositeという名前の通り、CompositeCommandが実行されるとそのコマンドに登録されている複数のDelegateCommandが実行される仕組みになっています。

- エントリーポイントでは、ApplicationCommandsをシングルトンで登録しています。

  ```cs
    namespace UsingCompositeCommands
    {
        public partial class App : PrismApplication
        {
            ...

            protected override void RegisterTypes(IContainerRegistry containerRegistry)
            {
                containerRegistry.RegisterSingleton<IApplicationCommands, ApplicationCommands>();
            }
        }
    }
  ```

- CompositeCommandsでは複数モジュールから利用されること意識してか、別パッケージ管理となっていました。以下が実際の定義です。
  
  ```cs
  namespace UsingCompositeCommands.Core
  {
      public interface IApplicationCommands
      {
          CompositeCommand SaveCommand { get; }
      }
  
      public class ApplicationCommands : IApplicationCommands
      {
          private CompositeCommand _saveCommand = new CompositeCommand();
          public CompositeCommand SaveCommand
          {
              get { return _saveCommand; }
          }
      }
  }
  ```

- 実際に、xamlにバインディングするときには通常のコマンドと同様にバインディングするだけでよいように作られています。

  ```xml
  <Window x:Class="UsingCompositeCommands.Views.MainWindow" ...>

    ...
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>

        <Button Content="Save" Margin="10" Command="{Binding ApplicationCommands.SaveCommand}"/>

        <TabControl Grid.Row="1" Margin="10" prism:RegionManager.RegionName="ContentRegion" />
    </Grid>
  </Window>
  ```

- CompositeCommands実行時に実行してほしいコマンドは、以下のように登録しておく必要があります。
  
  ```cs
  
  namespace ModuleA.ViewModels
  {
      public class TabViewModel : BindableBase
      {
          ...
  
          public TabViewModel(IApplicationCommands applicationCommands)
          {
              _applicationCommands = applicationCommands;
  
              UpdateCommand = new DelegateCommand(Update).ObservesCanExecute(() => CanUpdate);
  
              _applicationCommands.SaveCommand.RegisterCommand(UpdateCommand);
          }
  
          private void Update()
          {
              UpdateText = $"Updated: {DateTime.Now}";
          }       
      }
  }
  ```

- CompositeCommandsの定義は[ここ](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Commands/CompositeCommand.cs)にあります。
  - [CompositeCommands.RegisterCommand](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Commands/CompositeCommand.cs#L48)はここにあります。ICommand型のリストにコマンドを詰め込んでいきます。
  - [CompositeCommands.Execute](https://github.com/PrismLibrary/Prism/blob/master/src/Prism.Core/Commands/CompositeCommand.cs#L157)では、いったんキューに詰めなおし、そのキューが空になるまでループさせています。
    - 想像でしかありませんが、キューに詰めなおすタイミングでlockしていることから、非同期でも操作されても困らないようにしているのだと思われます。

## おわりに

今回はCompositeCommandsの利用方法を学びました。
このコマンドを利用すれば、閉じたりした場合に、一括で初期化できたりしそうですね。
次回、[13-IActiveAwareCommands](https://github.com/PrismLibrary/Prism-Samples-Wpf/tree/master/13-IActiveAwareCommands)について見ていこうと思います。