C# WPF gui 运行异步任务与终止

92 篇文章 9 订阅
92 篇文章 24 订阅

我有一个 WPF GUI,我想在其中按下一个按钮来开始一个很长的任务,而不会在任务期间冻结窗口。当任务正在运行时,我想获得进度报告,并且我想加入另一个按钮,可以在我选择的任何时间停止任务。

async和await:

1:你只能await在一个async方法中。

2:你只能await一个awaitable对象(即Task,ValueTask,Task<T>,IAsyncEnumerable<T>,等),这些对象环绕的的返回类型async的方法和await关键字解开他们。(参见包装和展开部分)

3:异步方法名称应始终以结尾Async以提高可读性并防止错误。

// Synchronous method:
TResult MethodName(params) { }

// Asynchronous method:
async Task<TResult> MethodNameAsync(params) { }

在async-await语法功能,让编译器放弃和收回在控制awaited Task中的async方法。

执行等待await任务完成并返回其结果,而不会阻塞主线程。

Task.RunTask在线程池中排队 a 。(除非它是一个纯操作。) 即该async方法不在另一个线程中运行。async并且await它们本身与线程创建没有任何关系。

所以通过放入async方法签名,你告诉编译器使用状态机来调用这个方法(目前没有线程)。然后通过运行一个Task你(重新)使用一个线程来调用任务内部的方法。通过执行await任务,您可以防止执行流越过该await行而不会阻塞 UI 线程。

private async void MyButton_ClickAsync(object sender, RoutedEventArgs e)
{
    Task task = Task.Run(()=>
        ExecuteLongProcedure(this, intParam1, intParam2, intParam3)
    );
    Task task = ExecuteLongProcedureAsync(this, intParam1, intParam2, intParam3);

    await task;
    task.Wait();
}

介绍完异步后,怎么在异步任务中停止任务

使用 CancellationTokenSource 终止线程。

<Window x:Class="ProgressExample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" SizeToContent="WidthAndHeight" Height="93.258" Width="316.945">
    <StackPanel>
        <Button x:Name="Button_Start" Click="Button_Click">Start</Button>
        <ProgressBar x:Name="ProgressBar_Progress" Height="20"  Maximum="100"/>
        <Button x:Name="Button_Cancel" IsEnabled="False" Click="Button_Cancel_Click">Cancel</Button>
    </StackPanel>
</Window>

按下停止按钮this.currentCancellationSource.Cancel 会终止线程

/// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        private CancellationTokenSource currentCancellationSource;

        public MainWindow()
        {
            InitializeComponent();
        }

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            // Enable/disabled buttons so that only one counting task runs at a time.
            this.Button_Start.IsEnabled = false;
            this.Button_Cancel.IsEnabled = true;

            try
            {
                // Set up the progress event handler - this instance automatically invokes to the UI for UI updates
                // this.ProgressBar_Progress is the progress bar control
                IProgress<int> progress = new Progress<int>(count => this.ProgressBar_Progress.Value = count);

                currentCancellationSource = new CancellationTokenSource();
                await CountToOneHundredAsync(progress, this.currentCancellationSource.Token);

                // Operation was successful. Let the user know!
                MessageBox.Show("Done counting!");
            }
            catch (OperationCanceledException)
            {
                // Operation was cancelled. Let the user know!
                MessageBox.Show("Operation cancelled.");
            }
            finally
            {
                // Reset controls in a finally block so that they ALWAYS go 
                // back to the correct state once the counting ends, 
                // regardless of any exceptions
                this.Button_Start.IsEnabled = true;
                this.Button_Cancel.IsEnabled = false;
                this.ProgressBar_Progress.Value = 0;

                // Dispose of the cancellation source as it is no longer needed
                this.currentCancellationSource.Dispose();
                this.currentCancellationSource = null;
            }
        }

        private async Task CountToOneHundredAsync(IProgress<int> progress, CancellationToken cancellationToken)
        {
            for (int i = 1; i <= 100; i++)
            {
                // This is where the 'work' is performed. 
                // Feel free to swap out Task.Delay for your own Task-returning code! 
                // You can even await many tasks here

                // ConfigureAwait(false) tells the task that we dont need to come back to the UI after awaiting
                // This is a good read on the subject - https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html
                await Task.Delay(100, cancellationToken).ConfigureAwait(false);

                // If cancelled, an exception will be thrown by the call the task.Delay
                // and will bubble up to the calling method because we used await!

                // Report progress with the current number
                progress.Report(i);
            }
        }

        private void Button_Cancel_Click(object sender, RoutedEventArgs e)
        {
            // Cancel the cancellation token
            this.currentCancellationSource.Cancel();
        }
    }

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值