/// <summary> /// Defines the method to be called when the command is invoked. /// </summary> /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can /// be set to null.</param> /// <param name="ignoreCanExecuteCheck">if set to <c>true</c>, the check on <see cref="Command{TExecuteParameter, TCanExecuteParameter}.CanExecute()" /> will be used before /// actually executing the action.</param> protected override async void Execute(TExecuteParameter parameter, bool ignoreCanExecuteCheck) { // Double check whether execution is allowed, some controls directly call Execute if (_execute == null || IsExecuting || (!ignoreCanExecuteCheck && !CanExecute(parameter))) { return; } var args = new CommandCanceledEventArgs(parameter); Executing.SafeInvoke(this, args); if (args.Cancel) { return; } if (_cancellationTokenSource != null) { _cancellationTokenSource.Dispose(); } _cancellationTokenSource = new CancellationTokenSource(); RaiseCanExecuteChanged(); var executionTask = _execute(parameter, _cancellationTokenSource.Token, _progress); try { Log.Info("Executing task command..."); await executionTask.ConfigureAwait(false); } catch (OperationCanceledException) { Log.Info("Task was canceled."); } catch (Exception ex) { Log.Error(ex, "Task ended with exception."); } finally { _cancellationTokenSource.Dispose(); _cancellationTokenSource = null; } if (executionTask.IsCanceled || executionTask.IsFaulted) { Canceled.SafeInvoke(this, new CommandEventArgs(parameter)); } else { RaiseExecuted(parameter); } RaiseCanExecuteChanged(); }
/// <summary> /// Defines the method to be called when the command is invoked. /// </summary> /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param> /// <param name="ignoreCanExecuteCheck">if set to <c>true</c>, the check on <see cref="System.Windows.Input.ICommand.CanExecute"/> will be used before actually executing the action.</param> protected override async void Execute(TExecuteParameter parameter, bool ignoreCanExecuteCheck) { if (IsExecuting) { return; } // It might be possible that the IsExecuting is used as a check whether the command can be executed again, // so use that as a check var canExecute = CanExecute(parameter); if (!canExecute) { return; } var args = new CommandCanceledEventArgs(parameter); Executing.SafeInvoke(this, args); if (args.Cancel) { return; } IsExecuting = true; RaiseCanExecuteChanged(); // Run the action on a new thread from the thread pool (this will therefore work in Silverlight and Windows Phone as well) #if NETFX_CORE await ThreadPool.RunAsync(state => #else ThreadPool.QueueUserWorkItem(state => #endif { // Skip the check, we already did that base.Execute(parameter, true); ReportProgress(() => { IsExecuting = false; if (IsCancelationRequested) { Canceled.SafeInvoke(this, () => new CommandEventArgs(parameter)); } else { RaiseExecuted(parameter); } IsCancelationRequested = false; }); }); }
/// <summary> /// Defines the method to be called when the command is invoked. /// </summary> /// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can /// be set to null.</param> /// <param name="ignoreCanExecuteCheck">if set to <c>true</c>, the check on <see cref="Command{TExecuteParameter, TCanExecuteParameter}.CanExecute()" /> will be used before /// actually executing the action.</param> protected override async Task ExecuteAsync(TExecuteParameter parameter, bool ignoreCanExecuteCheck) { var executeAsync = _executeAsync; // Double check whether execution is allowed, some controls directly call Execute if (executeAsync == null || IsExecuting || (!ignoreCanExecuteCheck && !CanExecute(parameter))) { return; } if (_cancellationTokenSource != null) { _cancellationTokenSource.Dispose(); } _cancellationTokenSource = new CancellationTokenSource(); var args = new CommandCanceledEventArgs(parameter); Executing.SafeInvoke(this, args); if (args.Cancel) { return; } RaiseCanExecuteChanged(); var executionTask = executeAsync(parameter, _cancellationTokenSource.Token, _progress); // Use TaskCompletionSource to create a separate task that will not contain the // exception that might be thrown. This allows us to let the users await the task // but still respect the SwallowExceptions property var tcs = new TaskCompletionSource <object>(); _task = tcs.Task; try { Log.Debug("Executing task command"); await executionTask.ConfigureAwait(false); } catch (OperationCanceledException) { Log.Debug("Task was canceled"); } catch (Exception ex) { Log.Error(ex, "Task ended with exception"); if (!SwallowExceptions) { throw; } } finally { _cancellationTokenSource.Dispose(); _cancellationTokenSource = null; tcs.TrySetResult(null); _task = null; } if (executionTask.IsCanceled) { Canceled.SafeInvoke(this, () => new CommandEventArgs(parameter)); } else { await RaiseExecutedAsync(parameter); } RaiseCanExecuteChanged(); }