我有一个帖子,想要用进度更新列表,但表单控件不是线程安全的。所以我学会了解决article。
问题是有更多的来源,每个来源都有自己的列表来显示进度。那么我如何使每个列表框都有自己的ThreadSafeSetText()
方法来清理代码?
delegate void SetTextCallback(string text);
private async void btnRun_Click(object sender, EventArgs e)
{
await Task.Run(() =>
{
importSource1();
});
//await Task.Run(() =>
//{
// importSource2();
//});
}
private void importSource1()
{
// db stuff in a Parallel.For
SetText("Result");
}
private void SetText(string text)
{
// InvokeRequired required compares the thread ID of the
// calling thread to the thread ID of the creating thread.
// If these threads are different, it returns true.
if (this.lstImportSource1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.lstImportSource1.Items.Insert(0, text);
}
}
答案 0 :(得分:0)
根据ImportSource
是执行数据库程序的方法的评论,我的建议使用async-await
aproach。
当您的代码执行“触及”外部资源(数据库,文件系统,Web API等)的操作时,Async-await
旨在实现更有效的资源使用。
因为在执行数据库查询(例如)期间,您的方法“什么都不做”,所以它只发送请求并等待响应。创建一个“无所事事”的新线程被视为浪费资源。
async-await
操作将在一个线程上执行(大多数时间),您只需使用UI控件。
您可以为每个过程创建自己的异步方法
public async Task ExecuteProcedure1Async()
{
using (var connection = new SqlConnection("connection string"))
using (var command = new SqlCommand("dbo.sqlProcedure1", connection))
{
command.CommandType = CommandType.StoredProcedure;
// Here execution will send request to the database
// and be returned to the caller of this method
await connection.OpenAsync();
// Continue after OpenAsync is completes and
// Here execution will again will be returned to the caller
await command.ExecuteCommandAsync();
// Continues after ExecuteCommandAsync is completed
}
}
可以为另一个存储过程创建类似的方法
以下所有程序将同时“几乎”执行 因为我们会在不等待回复的情况下发送请求 并且仅在所有程序完成时等待
private async Task ImportSource1Async()
{
// Because asynchronoud method returns Task
// We can create collection of tasks and "await" them all
// after they have been started
var tasks = new[]
{
ExecuteProcedure1Async(),
ExecuteProcedure2Async(),
ExecuteProcedure3Async()
};
await Task.WhenAll(tasks);
}
然后,您可以在ImportSourceAsync
eventhandler中将所有button_click
方法组合在一起,并使用UI控件。
private async void btnRun_Click(object sender, EventArgs e)
{
await ImportSource1Async();
lstImportSource1.Items.Insert(0, "Import source 1 complete");
await ImportSource2Async();
lstImportSource1.Items.Insert(0, "Import source 2 complete");
await ImportSource3Async();
lstImportSource1.Items.Insert(0, "Import source 3 complete");
}