我有以下自定义Task
代码:
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()
方法调用的形式显示:
如何改进代码以使事情正常运行?
答案 0 :(得分:1)
根据您在注释中提供的其他信息,我认为您应该尝试将代码转换为完全使用async
/ await
。这将涉及将所有ADO.NET函数转换为.NET 4.5中添加到ADO的新async methods。这将消除所有的Task.Run
调用,以及为将控制权调回UI线程而进行的混乱的InvokeRequired
和BeginInvoke
调用。
我认为您会发现,如果实施正确,您甚至不需要特殊的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
修饰符充当编译器的标记,以将方法转换为状态机。编译将对方法中的代码进行分段,并在每次await
调用时将其分解为单独的状态。调用函数时,将运行第一个状态(直至await
所在的位置),然后函数返回到调用方。当正在等待的函数返回时,其后的代码(在下一个状态中)将作为继续调用。在状态之间共享的所有数据(例如局部变量)都移到一个对象中,该对象传递到每个状态的延续中。