大丈夫。タスクベースの非同期パターンを使用すると、要件は簡単です。
AsynchronousCommand
フレームワークにまだないものが必要です。少しの努力で自分で作ることができます。
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync(object parameter);
}
次のようになるこのインターフェースの複合実装が必要です
public class AsyncCompositeCommand : IAsyncCommand
{
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
private readonly IEnumerable<IAsyncCommand> commands;
private readonly Action<object> executedCallback;
public AsyncCompositeCommand(IEnumerable<IAsyncCommand> commands, Action<object> executedCallback)
{
this.commands = commands;
this.executedCallback = executedCallback;
}
public bool CanExecute(object parameter)
{
return commands.Any(x => x.CanExecute(parameter));
}
public async Task ExecuteAsync(object parameter)
{
var pendingTasks = commands.Select(c=> c.ExecuteAsync(parameter))
.ToList();
await Task.WhenAll(pendingTasks);
executedCallback(parameter);//Notify
}
public async void Execute(object parameter)
{
await ExecuteAsync(parameter);
}
}
上記のクラスExecuteAsync
では、他の子コマンドを並行して開始します。シーケンシャルにしたい場合は、ExecuteAsync
メソッドを以下の実装に置き換えることができます。
public async Task ExecuteAsync(object parameter)
{
foreach (var cmd in commands)
{
await cmd.ExecuteAsync(parameter);
}
executedCallback(parameter);//Notify
}
executedCallback
すべての子コマンドが完了したときに呼び出されるデリゲートです。ウィンドウを閉じるコードをそのデリゲートにラップすることができます。
ビューモデルは次のようになります。
public class ViewModel
{
public ICommand SaveCommand { get; private set; }
public ViewModel()
{
SaveCommand = new AsyncCompositeCommand(new IAsyncCommand[]
{
command1,
command2,
...
},
param => Console.WriteLine("Done"));
}
}
ViewModel.SaveCommand
UI でプロパティをバインドする方法はあなた次第です。