我想在单击wpf按钮后执行长时间运行的任务。这是我做的。
private void Start(object sender, RoutedEventArgs e) { for (int i = 0; i < 10; i++) { Thread.Sleep(2000); // simulate task } }
问题是,这会使wpf gui无法响应。我也想允许取消并每1秒报告一次进度。我将代码扩展如下。
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; }
我的目标平台是.NET 4.5。推荐的方法是什么?
谢谢。
我以为我在这里回答了你的问题。如果您需要有关如何使用Task Parallel Library进行操作的更多示例代码,请使用CancellationTokenSource和IProgress<T>,这里是:
CancellationTokenSource
IProgress<T>
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<int>((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<int> 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; }