[英]Task.Run(() => Method()); doesn't run the method?
In my WPF application: 在我的WPF应用程序中:
using System;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using System.Diagnostics;
namespace CloudKey
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
AuthText.Visibility = Visibility.Hidden;
}
private async void button_Click(object sender, RoutedEventArgs e)
{
AuthText.Visibility = Visibility.Visible;
await Task.Run(() => Authenticate());
Task.Factory.StartNew(() => Authenticate());
Task.Run(() => Authenticate());
Authenticate();
}
void Authenticate()
{
//Do Stuff
}
}
}
No matter which way I try to call Authenticate
with Tasks
it just doesn't run. 无论我尝试以哪种方式调用“通过Tasks
进行Authenticate
,它都不会运行。 Am I using Task
wrong? 我使用Task
错误?
Using await (and async) causes an exception to be thrown: 使用await(和async)会引发异常:
System.InvalidOperationException was unhandled Message: An unhandled exception of type 'System.InvalidOperationException' occurred in mscorlib.dll Additional information: The calling thread cannot access this object because a different thread owns it. 未处理System.InvalidOperationException消息:mscorlib.dll中发生了'System.InvalidOperationException'类型的未处理异常。其他信息:调用线程无法访问此对象,因为其他线程拥有它。
Using just Task.Run or Task.Factory.StartNew causes the Authenticate method not to be run at all. 仅使用Task.Run或Task.Factory.StartNew会导致完全不执行Authenticate方法。 If I add a breakpoint to the Authenticate method it isn't reached. 如果我将断点添加到Authenticate方法中,则无法实现。
Just calling the method with Authenticate() runs the entire method without issue, but it freezes the UI making "AuthText.Visibility = Visibility.Visible;" 只需使用Authenticate()调用该方法即可运行整个方法,而不会出现问题,但是它将冻结UI,使之成为“ AuthText.Visibility = Visibility.Visible;”。 useless. 无用。
To be honest, I really just want the UI to update with the message "Authenticating..." and THEN run everything in the method when I click the button. 老实说,我真的只希望UI更新消息“ Authenticating ...”,然后在单击按钮时运行方法中的所有内容。 Is there perhaps an easier way to do that? 也许有更简单的方法做到这一点?
THIS IS THE WORKING CODE FOR REFERENCE: 这是参考的工作代码:
using System;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using System.Diagnostics;
using System.Threading.Tasks;
namespace CloudKey
{
/// <summary>
/// Interaction logic for Page1.xaml
/// </summary>
public partial class Page1 : Page
{
public Page1()
{
InitializeComponent();
//private void PasswordBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { button_Click } }
AuthText.Visibility = Visibility.Hidden;
}
private void button_Click(object sender, RoutedEventArgs e) //ON CONTINUE BUTTON CLICK
{
AuthText.Visibility = Visibility.Visible;
Task.Run(() => Authenticate());
}
void Authenticate()
{
Dispatcher.Invoke(
() =>
{
//ALL MY CODE HERE;
});
}
}
}
The issue is that you're not waiting for the asynchronous task to complete, so it appears like "nothing happens" - when in fact something does happen. 问题是您不等待异步任务完成,因此看起来好像“什么都没有发生”-实际上确实发生了。 When you invoke either Task.Run
or Task.Factory.StartNew
you're essentially performaing a fire-and-forget, unless you correctly handle the Task
. 当您调用Task.Run
或Task.Factory.StartNew
,除非您正确处理Task
,否则实际上就是在执行即Task.Run
即Task.Factory.StartNew
。
private async void button_Click(object sender, RoutedEventArgs e)
{
await Task.Run(() => Authenticate()); // Stuff happens
}
void Authenticate()
{
// DO STUFF
}
In the example above adding the keyword async
to the event handler allows the method to utilize the await
keyword. 在上面的示例中,将关键字async
添加到事件处理程序允许该方法利用await
关键字。 The await
keyword is where all the magic really occurs...but it will then work as you'd expect, ie; await
关键字是所有魔术真正发生的地方……但是它将按您期望的那样工作,即; "Stuff happens". “事情发生了”。
When I do beat Stephen Cleary to these answers I usually point people to his blogs, this one in particular should help clarify this for you. 当我击败斯蒂芬·克雷蒂(Stephen Cleary)时,通常会向人们指向他的博客, 这一博客尤其应为您澄清这一点。
Note 注意
Writing an async void
is strongly discouraged! 强烈建议不要编写async void
! The only exception is in your example where you are applying it to an event handler. 唯一的例外是在示例中将其应用于事件处理程序。 Finally, when using Task
, and Task<T>
with the async / await
keywords - do so through the entire stack. 最后,当使用Task
和Task<T>
以及async / await
关键字时,请在整个堆栈中使用。 I would change your Authenticate
method to return a Task
for example, such that it can be awaited. 我会更改您的Authenticate
方法以返回一个Task
,例如,可以等待它。 Try invoking Task.Run
at the lowest level possible. 尝试调用Task.Run
尽可能最低的级别。
private async void button_Click(object sender, RoutedEventArgs e)
{
await Authenticate(); // Stuff happens
}
Task Authenticate()
{
return _authModule.Authenticate();
}
Update 更新资料
Based on your comments, do the following: 根据您的评论,执行以下操作:
private void button_Click(object sender, RoutedEventArgs e)
{
bool authenticated = false;
try
{
AuthText = "Authenticating...";
authenticated = Authenticate(); // Stuff happens
}
finally
{
AuthText = authenticated ? "Authenticated" : "Oops!";
}
}
bool Authenticate()
{
// Return if auth was successful
}
When you modify UI stuff in a new thread then you need to use Dispatcher.Invoke
or you can use InvokeAsync
在新线程中修改UI内容时,您需要使用Dispatcher.Invoke
,也可以使用InvokeAsync
private void Button_Click( object sender, RoutedEventArgs e ) { Task.Run( () => Authenticate() ); }
public void Authenticate()
{
Dispatcher.Invoke(
() =>
{
ClickButton.Content = "Text Changed";
} );
}
By using Dispatcher
You are telling WPF that run this code block on main thread which has access to update your GUI controls. 通过使用Dispatcher
您正在告诉WPF在有权更新您的GUI控件的主线程上运行此代码块。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.