C# 仅在异步任务完成后显示的表单

C# 仅在异步任务完成后显示的表单,c#,multithreading,asynchronous,C#,Multithreading,Asynchronous,我有一个自定义任务代码: public static async Task Run(this CustomForm parent, Action action) { parent.Enabled = false; using (Caricamento form = new Caricamento()) { form.TopLevel = true; form.TopMost = true; form.Show();

我有一个自定义
任务
代码:

public static async Task Run(this CustomForm parent, Action action)
{
    parent.Enabled = false;
    using (Caricamento form = new Caricamento())
    {
        form.TopLevel = true;
        form.TopMost = true;
        form.Show();
        await Task.Run(action);
    }
    parent.Enabled = true;
}
async
任务完成之前,无法正确加载gif动画和表单中的文本

    ListMessaggi listForm = new ListMessaggi(ListMessaggi.Tipo.Entrata);
    listForm.FormClosing += (o, args) =>
    {
        if (this.Controls.Count == 2)
        {
            args.Cancel = true;
        }
    };

    listForm.FormBorderStyle = FormBorderStyle.None;
    listForm.Dock = DockStyle.Fill;
    listForm.TopLevel = false;
    panel.Controls.Add(listForm);
    listForm.Show();
然后,在
listForm.Show()
方法调用中显示的表单中,我得到:

最后,这是异步任务运行时显示的结果:


如何改进代码以使其正常工作?

根据您在评论中提供的其他信息,我认为您应该尝试将代码转换为完全使用
async
/
wait
。这将涉及将所有ADO.NET函数转换为在.NET 4.5中添加到ADO的新函数。这将消除所有
任务。运行
调用,以及将控件封送回UI线程所需的混乱的
调用
开始调用
调用

我想你会发现,如果实施得当,你甚至不需要特殊的
Run
扩展方法;您将能够让所有代码在线,就像在“传统的.net开发”中一样

例如,您可以使用这样的代码在表单的
load
事件中响应地加载数据,而不锁定UI

public async void Form1_Load(object sender, EventArgs e)
{
    var data = await _dataProvider.GetSomeDataFromTheDatabase(aTotallyMadeUpVariable);
    this.MyDataGrid.DataSource = data;
}
完全相同的模式适用于组合框和按钮上的事件处理程序


另外,WinForms中的事件处理程序实际上是
async void
方法合法有效的唯一地方。其他一切,包括从事件处理程序中调用的
async
方法,都应该是
Task
返回函数


作为
async
/
await
上的一个“入门”,这就是我在上面的示例中避免阻塞UI线程的方法


函数上的
async
修饰符充当编译器的标记,将方法转换为状态机。编译将在方法中对代码进行分段,在每次
wait
调用中将代码分解为不同的状态。调用函数时,将运行第一个状态(直到
await
所在的位置),然后函数返回调用方。当被等待的函数返回时,它后面的代码(在下一个状态中)将作为一个延续被调用。状态之间共享的任何数据(如局部变量)都会移动到一个对象,该对象会传递到每个状态的延续中。

改进它的“最佳”方法是让
Run
方法采用
Func
而不是
操作,然后等待它的
Invoke
方法,不要使用
任务。运行
@BradleyUffner粘贴一些代码,如果它有效,我会接受你的答案。很可能我的想法不会像听起来那么简单,这就是为什么我没有将它作为答案发布。您可能需要重新构建大部分应用程序才能使其正常工作。我需要更多关于您实际想要做什么(以及为什么)的信息。您能举一个例子说明您在
UpdateGrid
中正在做什么吗?它的名字意味着它在UI中做一些事情,但是在任务内部做。Run
意味着它在UI线程之外执行。这可能就是锁定的原因。@BradleyUffner UpdateGrid实际上访问与数据库接口的业务方法,例如
myModel.GetAll()
*返回
List
*并且
List
将被分配给具有适当筛选等功能的数据网格
UpdateGrid
将在窗体加载和对话框关闭时被调用(如编辑项,打开网格的窗体的
FormClosing
将通过相同的方法刷新)。我的整个应用程序遵循此逻辑,此时我正试图实现异步加载以避免UI锁定No,
async
/
await
模式的全部目的是允许UI不阻塞UI线程,并保持应用程序的响应性,而不必处理线程问题。我在答案的底部添加了一个小的“async primer”blob,这应该让你开始了解如何避免阻塞UI的基础知识。完整的细节有点复杂,超出了我在这个答案中所能解释的范围。这就是结果。它可以工作,但是加载表单的UI在某个点被锁定,直到表单完全加载后才会旋转。使用的代码:,方法代码:getEnterata中仍有一些阻塞调用需要转换为异步对应调用。我看到的第一个问题是您需要更改
连接。打开
等待连接。OpenAsync
。这是正确执行
async
/
等待
模式的一个棘手部分。它确实必须是“一路异步”的。即使是一个阻塞调用也会使UI停滞。从一开始就做这件事要比尝试重新适应现有的复杂项目容易得多。如果您想了解更多信息,Stephen Cleary在async/Wait上发表了一些精彩的博客文章。这是另一个很好的起点: