和标签:使用系统;使用System.IO;使用System.Threading.Tasks;使用System.Windows.Forms;namespaceWindowsFormsApplication1{publicpartialclassForm1:Form{publicForm1(){InitializeComponent();}privateasyncvoidbutton1_Click(objectsender,EventArgse){awaitRun();}privateasyncTaskRun(){awaitTask.Run(async()=>{awaitFile.AppendText("temp.dat").WriteAsync("a");label1.Text="test";});}}}这是我正在处理的实际应用程序的简化版本。我的印象是,通过在Task.Run中使用async/await,我可以设置label1.Text属性。但是,在运行这段代码时,出现错误,提示我不在UI线程上,无法访问控件。为什么我无法访问标签控件?当您使用Task.Run()时,您不希望代码在当前上下文中运行,所以这正是发生的情况。但是没有必要在代码中使用Task.Run()。正确编写的异步方法不会阻塞当前线程,因此您可以直接从UI线程使用它们。如果这样做,await将确保该方法在UI线程上恢复。这意味着,如果您像这样编写代码,它将起作用:privateasyncvoidbutton1_Click(objectsender,EventArgse){awaitRun();}privateasyncTaskRun(){awaitFile.AppendText("temp.dat").WriteAsync("a");label1.Text="测试";}试试这个privateasyncTaskRun(){awaitTask.Run(async()=>{awaitFile.AppendText("temp.dat").WriteAsync("a");});label1.Text="测试";}或privateasyncTaskRun(){awaitFile.AppendText("temp.dat").WriteAsync("a");label1.Text="测试";}或privateasyncTaskRun(){vartask=Task.Run(async()=>{awaitFile.AppendText("temp.dat").WriteAsync("a");});varcontinuation=task.ContinueWith(antecedent=>label1.Text="test",TaskScheduler.FromCurrentSynchronizationContext());awaittask;//我觉得这里的await是多余的}async/await不保证会在UI线程中运行。await会捕获当前的SynchronizationContext,并在任务完成后继续执行捕获的上下文。因此,在您的情况下,您有一个位于Task.Run的嵌套await,因此第二个await将捕获不是UiSynchronizationContext的上下文,因为它正在由ThreadPool的WorkerThread执行。这回答了你的问题了吗?试试这个:替换label1.Text="test";与SetLabel1Text("测试");并将以下内容添加到您的课程中:privatevoidSetLabel1Text(stringtext){if(InvokeRequired){Invoke((Action)SetLabel1Text,text);返回;}label1.Text=文本;如果您不在UI线程上,则InvokeRequired返回true。Invoke()方法获取委托和参数,切换到UI线程,递归调用方法。在Invoke()调用之后返回,因为在Invoke()返回之前已递归调用该方法。如果方法调用时刚好在UI线程,InvokeRequired为false,直接赋值。为什么要使用Task.Run?启动一个新的工作线程(cpubound),它会导致你的问题。您可能应该这样做:privateasyncTaskRun(){awaitFile.AppendText("temp.dat").WriteAsync("a");label1.Text="测试";}await确保您将继续使用相同的上下文,除非您使用.ConfigureAwait(false);因为它在不同的线程上,所以不允许跨线程调用。您需要将“上下文”传递给您正在启动的线程。在这里查看示例:http://reedcopsey.com/2009/11/17/synchronizing-net-4-tasks-with-the-ui-thread/我会给你我最新的答案我已经给出了异步理解.解决方法如您所知,当您调用异步方法时,您需要将其作为任务运行。这是一个快速的控制台应用程序代码,您可以将其用作参考,它将使概念易于理解。使用系统;使用系统线程;使用System.Threading.Tasks;publicclassProgram{publicstaticvoidMain(){Console.WriteLine("开始发送邮件异步任务");任务task=newTask(SendMessage);任务。开始();Console.WriteLine("更新数据库");更新数据库();while(true){//虚拟等待后台发送邮件。如果(task.Status==TaskStatus.RanToCompletion){break;}}}publicstaticasyncvoidSendMessage(){//调用TaskOfTResult_MethodAsyncTaskreturnedTaskTResult=MailSenderAsync();boolresult=awaitreturnedTaskTResult;如果(结果){更新数据库();}Console.WriteLine("邮件已发送!");}privatevoidstaticUpdateDatabase(){for(vari=1;iMailSenderAsync(){Console.WriteLine("SendMailStart.");for(vari=1;i在这里我尝试开始一个名为发送邮件的任务.暂时我想在后台运行发送邮件任务时更新数据库。数据库更新发生后,它正在等待发送邮件任务完成。但是,使用这种方法很明显我可以运行任务在后台并继续使用原始(主)线程。以上就是C#学习教程:在WinForms上使用async/await访问Task.Run中UI控件共享的所有内容。如果对你有用,需要了解更多C#学习教程,希望大家多多关注——本文来自网络收藏,不代表立场,如涉及侵权,请点击有权联系管理员删除。如需转载请注明出处:
