【发布时间】:2021-04-21 08:59:03
【问题描述】:
我正在尝试异步显示一个进度表,说明应用程序正在运行,而实际应用程序正在运行。
如下this question,我有以下几点:
主窗体:
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
async Task<int> LoadDataAsync()
{
await Task.Delay(2000);
return 42;
}
private async void Run_Click(object sender, EventArgs e)
{
var runningForm = new RunningForm();
runningForm.ShowRunning();
var progressFormTask = runningForm.ShowDialogAsync();
var data = await LoadDataAsync();
runningForm.Close();
await progressFormTask;
MessageBox.Show(data.ToString());
}
}
进度表
public partial class RunningForm : Form
{
private readonly SynchronizationContext synchronizationContext;
public RunningForm()
{
InitializeComponent();
synchronizationContext = SynchronizationContext.Current;
}
public async void ShowRunning()
{
this.RunningLabel.Text = "Running";
int dots = 0;
await Task.Run(() =>
{
while (true)
{
UpadateUi($"Running{new string('.', dots)}");
Thread.Sleep(300);
dots = (dots == 3) ? 0 : dots + 1;
}
});
}
public void UpadateUi(string text)
{
synchronizationContext.Post(
new SendOrPostCallback(o =>
{
this.RunningLabel.Text = text;
}),
text);
}
public void CloseThread()
{
synchronizationContext.Post(
new SendOrPostCallback(o =>
{
this.Close();
}),
null);
}
}
internal static class DialogExt
{
public static async Task<DialogResult> ShowDialogAsync(this Form form)
{
await Task.Yield();
if (form.IsDisposed)
{
return DialogResult.OK;
}
return form.ShowDialog();
}
}
上面的工作正常,但是当我从另一个人的外面打电话时它不起作用。这是我的控制台应用程序:
class Program
{
static void Main(string[] args)
{
new Test().Run();
Console.ReadLine();
}
}
class Test
{
private RunningForm runningForm;
public async void Run()
{
var runningForm = new RunningForm();
runningForm.ShowRunning();
var progressFormTask = runningForm.ShowDialogAsync();
var data = await LoadDataAsync();
runningForm.CloseThread();
await progressFormTask;
MessageBox.Show(data.ToString());
}
async Task<int> LoadDataAsync()
{
await Task.Delay(2000);
return 42;
}
}
观察调试器发生的情况,进程到达await Task.Yield() 并且永远不会进展到return form.ShowDialog(),因此您永远不会看到RunningForm。然后进程转到LoadDataAsync() 并永远挂在await Task.Delay(2000)。
为什么会这样?这与Tasks 的优先级如何(即:Task.Yield())有关吗?
【问题讨论】:
-
我相信您的任务不会自己挂起,而是您的问题是由于尝试在控制台应用程序中建立基于 WinForms 的 UI 而没有设置消息泵(这是WinForms UI 工作)。尝试以与此答案中所示类似的方式实例化和运行您的主表单:stackoverflow.com/a/277776/2819245。尝试一下,看看它是否能改善(或改变)行为。
-
另外,由于您使用任务(因此可能使用多个线程),请注意您在程序的主线程中创建消息泵(即执行
Application.Run)而不是在某个后台线程中。 -
正如@elgonzo 指出的那样,您链接的代码(我是其作者)旨在从带有消息循环的 WinForms UI 线程运行。你说 " "但是当我从另一个人的外面打电话时它不起作用。这是我的控制台应用程序...” 那么,您最终需要从另一个表单还是从非 UI 工作线程运行它?
-
@noseratio 我不需要它,我更想知道为什么它适用于 WinForms 而不适用于控制台应用程序。
标签: c# .net winforms async-await console