【问题标题】:Using asynchronous functions with UI synchronously将异步函数与 UI 同步使用
【发布时间】:2015-02-23 20:21:20
【问题描述】:

我有一个应用程序(WinForms)。它只是抓取一些数据,对其进行一些处理,然后将结果上传到某个云存储。我现在正在使用一些第三方代码来为我处理云存储的身份验证。此代码将创建一个 WinForm,它承载一个浏览器控件,如果用户尚未为应用程序提供使用云存储的凭据和权限,则会弹出该控件。在我的程序开始执行它的操作之前,我想确保我已经通过身份验证,因此在程序 (Program.cs) 的 Main() 循环中,我想使用第三方库对云存储进行身份验证并阻止我的实际代码(//myCode)执行,直到它完成。 “不幸的是”该库是异步的,我今天花了大部分时间试图获得我刚刚描述的行为 - 我的问题实际上是“使异步函数同步”,但我见过的一般答案似乎不适合我。

所以我有这样的东西

static void Main(string[] args)
{
OAuth.LoginAuthAsync("clientID", "client_secret", ...) 
//Don't want to get here until LoginAuthAsync is done 
application.run(myForm); //myCode
}

但这会弹出网络浏览器并运行我的代码,我希望只有在网络 OAuth.LoginAuthAsync 完成后才会发生这种情况。

我不是整个 TPL 库方面的专家,但我已经花了一些时间来研究我认为应该可行但不可行的东西。我试过了:

我试过了

        Task.Run(async () =>
            {
                OAuth.LoginAuthAsync("123456", "asdasd", ...));
    ).Wait();

这会在第三方库中引发错误

System.Threading.ThreadStateException:无法实例化 ActiveX 控件“8856f961-340a-11d0-a96b-00c04fd705a2”,因为当前线程不在单线程单元中。 在 System.Windows.Forms.WebBrowserBase..ctor(字符串 clsidString) 在 System.Windows.Forms.WebBrowser..ctor()

然后我尝试了

        Thread tx = new Thread(() => OAuth.LoginAuthAsync("123456","asdasd", ……..));
        tx.SetApartmentState(ApartmentState.STA);
        tx.Start();
        tx.Join();

但这只是弹出窗口并立即消失,然后 //myCode 执行。

任何人都知道我可以在这里做什么。我尝试将方法移动到 myForm _Load 事件中(即从 application.run 调用的 myForm),但我遇到了同样的问题。

非常感谢

附:我不想使用任何其他第三方库。

【问题讨论】:

  • 当你“完成”登录时,你能捕捉到那个事件并把它扔回去然后调用加入吗?也可以在调用 application.run(yourForm) 之前将它放在应用程序启动中
  • 检查this

标签: c# asynchronous task-parallel-library webbrowser-control live-sdk


【解决方案1】:

您可以使用从OAuth.LoginAuthAsync 返回的Task 上的Wait() 方法阻止并等待代码完成。这适用于控制台应用程序,但可能会导致 GUI/ASP 应用程序中出现deadlock

static void Main(string[] args)
{
    OAuth.LoginAuthAsync("clientID", "client_secret", ...).Wait();

    //Don't want to get here until LoginAuthAsync is done 
    application.run(myForm); //myCode
}

对于 GUI 应用程序,最好将相关方法 async 然后 await 调用到 OAuth.LoginAuthAsync 但是 Main 不能是 async。如果您将方法移动到 myForm_Load 方法中,您应该能够执行 await 调用:

public async void myForm_Load(object o, EventArgs e)
{ 
     await OAuth.LoginAuthAsync("clientID", "client_secret", ...);
}

在我看来这是更好的解决方案。

【讨论】:

  • 感谢您的回复。不幸的是,第一种方法导致 GUI 死锁(只是一个带有等待光标的空白表单)。第二种方法也不起作用 - 在打开登录窗口的同时继续正常执行(而不是我所追求的对话行为)
  • 弹出一个对话框然后在该对话框的Load 事件处理程序中调用OAuth.LoginAuthAsync 怎么样?
猜你喜欢
  • 2016-08-20
  • 2012-07-25
  • 2013-12-25
  • 1970-01-01
  • 2013-07-12
  • 1970-01-01
  • 1970-01-01
  • 2021-07-16
相关资源
最近更新 更多