c# - C#:在任务中打开 webbrowser --> 当前 STA 问题
问题描述
一般的:
- WPF 应用程序
- 使用 mahapps.metro
- 使用 mahapps 进度对话框
我想达到什么
- 打开 mahapps 进度对话框
- 在进度对话框中做一些事情
- 其中一项工作是为用户登录打开一个 webbrowser 元素 --> 登录后我得到了 cookie
- 仅在登录过程(任务)之后才做一些事情
当前问题
问题是,我必须为 mahapps 进度对话框创建一个任务,如下所示...
public async void startWork(view)
{
MahApps.Metro.Controls.MetroWindow window = Window.GetWindow(view) as MahApps.Metro.Controls.MetroWindow;
if (window != null)
{
var controller = await window.ShowProgressAsync("Please wait...", "Progress message");
controller.Maximum = 100;
await Task.Run(() => {
Login.RunAuthentification(controller, IDApp, IDToken, BaseUrl);
});
await controller.CloseAsync();
}}
在RunAuthentification 中,我有一个 webbrowser 的功能,看起来像这样
public static async Task<string> openLogin(string _authorizationUrl)
{
string sessionId = null;
if (_authorizationUrl.Length == 0)
{
throw new ArgumentException("Authorization url cannot be empty");
}
// The method should return based on an event.
// We need a Semaphore which we can then be released in the event handler
var signal = new System.Threading.SemaphoreSlim(0, 1);
// Create a WindowsForms window
var window = new System.Windows.Forms.Form
{
Text = "Please provide your login ...",
Size = new System.Drawing.Size(800, 545)
};
// Create a WindowsForms WebBrowser element
var browser = new System.Windows.Forms.WebBrowser
{
Dock = DockStyle.Fill,
Url = new Uri(_authorizationUrl)
};
// Add the browser to the window
window.Controls.Add(browser);
// If the window is closed, release the signal so the async task will be completed
window.Closed += (sender, args) => signal.Release();
// We will listen for any change of the url and wait for the authorization code.
// The browser might be redirected multiple times
browser.DocumentCompleted += (sender, eventArgs) =>
{
Console.WriteLine(eventArgs.Url.ToString());
if (eventArgs.Url.AbsolutePath.EndsWith("/confirmed"))
{
var cookies = browser.Document?.Cookie.Split(';')
.Select(keyValueStr => keyValueStr.Split('='))
.ToDictionary(arr => arr[0].Trim(), arr => arr[1].Trim());
cookies?.TryGetValue("SESSION", out sessionId);
window.Close();
}
};
// Show the window
window.ShowDialog();
// Wait until the signal is set
await signal.WaitAsync();
return sessionId;
}
现在我收到错误消息,我无法访问网络浏览器,因为实际线程不是 STA。有谁知道我如何优雅地解决这个问题?
解决方案
您将需要使用 Dispatcher 或 DispatcherSynchronizationContext 将您的任务中的调用“编组”到主 UI 线程。以下是使用 DispatcherSynchronizationContext 的方法:
public async void startWork(view)
{
MahApps.Metro.Controls.MetroWindow window = Window.GetWindow(view) as MahApps.Metro.Controls.MetroWindow;
if (window != null)
{
var controller = await window.ShowProgressAsync("Please wait...", "Progress message");
controller.Maximum = 100;
//capture the current SynchronizationContext
var context = SynchronizationContext.Current;
await System.Threading.Tasks.Task.Run(() =>
{
//use the context to marshal the call on the main UI thread
context.Send((o) => Login.RunAuthentification(controller, IDApp, IDToken, BaseUrl), null);
});
await controller.CloseAsync();
}
}
https://docs.microsoft.com/en-us/dotnet/api/system.windows.threading.dispatcher
推荐阅读
- byte - 当我们想用私有协议(不是http)在不同服务器之间传输文件时,使用字节或字符串来定义字段更好吗?
- c# - wcf服务c#.net框架4.5.1
- angular - 在角度/电子应用程序上将图像转换为 base64 URI
- r - 如何合并数据框中的行
- json - 如何使用 JMeter 从 JSON 响应中存在的 URL 中提取子字符串
- android-studio - 未处理的异常:MissingPluginException(在通道 sms_autofill 上找不到方法 listenForCode 的实现)
- php - 如何在 PHP 中删除 JSON 元素?
- python - LSTM 始终预测恒定值
- javascript - 使用 Gsuit 随机化谷歌表单部分?
- python - numpy.ndarray 中的行组合