¿Cómo ejecutar una tarea en el fondo de wpf mientras se puede proporcionar un informe y permitir la cancelación?

Quiero ejecutar una tarea de ejecución larga después de hacer clic en un botón wpf. Aquí lo que hice.

private void Start(object sender, RoutedEventArgs e) { for (int i = 0; i < 10; i++) { Thread.Sleep(2000); // simulate task } } 

El problema es que esto hará que wpf gui no responda. También me gustaría permitir la cancelación e informar el progreso cada 1 segundo. Amplío el código como abajo.

  DispatcherTimer dispatcherTimer = new DispatcherTimer(); // get progress every second private int progress = 0; // for progress reporting private bool isCancelled = false; // cancellation private void Start(object sender, RoutedEventArgs e) { InitializeTimer(); // initiallize interval timer Start(10); // execute task } private void InitializeTimer() { dispatcherTimer.Tick += dispatcherTimer_Tick; dispatcherTimer.Interval = new TimeSpan(0,0,1); dispatcherTimer.Start(); } private void dispatcherTimer_Tick(object sender, EventArgs e) { Logger.Info("Current loop progress " + progress); // report progress } private void Cancel(object sender, RoutedEventArgs e) // cancel button { isCancelled = true; } private int Start(int limit) { isCancelled = true; progress = 0; for (int i = 0; i < limit; i++) { Thread.Sleep(2000); // simulate task progress = i; // for progress report if (isCancelled) // cancellation { break; } } return limit; } 

Mi plataforma de destino es .NET 4.5. cual es la manera recomendada para hacer esto?

Gracias.

Creí haber respondido tu pregunta aquí . Si necesita más código de muestra sobre cómo hacer esto usando Task Parallel Library, con CancellationTokenSource e IProgress , aquí está:

 Action _cancelWork; private async void StartButton_Click(object sender, RoutedEventArgs e) { this.StartButton.IsEnabled = false; this.StopButton.IsEnabled = true; try { var cancellationTokenSource = new CancellationTokenSource(); this._cancelWork = () => { this.StopButton.IsEnabled = false; cancellationTokenSource.Cancel(); }; var limit = 10; var progressReport = new Progress((i) => this.TextBox.Text = (100 * i / (limit-1)).ToString() + "%"); var token = cancellationTokenSource.Token; await Task.Run(() => DoWork(limit, token, progressReport), token); } catch (Exception ex) { MessageBox.Show(ex.Message); } this.StartButton.IsEnabled = true; this.StopButton.IsEnabled = false; this._cancelWork = null; } private void StopButton_Click(object sender, RoutedEventArgs e) { this._cancelWork?.Invoke(); } private int DoWork( int limit, CancellationToken token, IProgress progressReport) { var progress = 0; for (int i = 0; i < limit; i++) { progressReport.Report(progress++); Thread.Sleep(2000); // simulate a work item token.ThrowIfCancellationRequested(); } return limit; } 

BackgroundWorker es lo que está buscando en lugar de DispatcherTimer.

Proporciona soporte de Cancelación (a través de WorkerSupportsCancellation ) y reporta el progreso en el hilo de UI (a través de WorkerReportsProgress ).

Consulte el excelente artículo detallado aquí – Cómo utilizar BackgroundWorker .