C# 在单独的线程中运行返回对象的数据库访问任务并保持UI响应的最佳方法?
[Windows窗体应用程序和.NET 4.0] 我需要执行返回对象(类列表或简单类)的数据库访问方法 我还需要在主线程进行初始化时打开响应的表单 我需要在不同的线程上运行它们,以保持用户界面的响应性,当然,还需要能够将结果传递回主线程以进行UI更新 我一直在阅读有关这方面各种方法的书籍 我理解我的工作可以通过以下方式完成:C# 在单独的线程中运行返回对象的数据库访问任务并保持UI响应的最佳方法?,c#,.net,multithreading,data-access-layer,splash-screen,C#,.net,Multithreading,Data Access Layer,Splash Screen,[Windows窗体应用程序和.NET 4.0] 我需要执行返回对象(类列表或简单类)的数据库访问方法 我还需要在主线程进行初始化时打开响应的表单 我需要在不同的线程上运行它们,以保持用户界面的响应性,当然,还需要能够将结果传递回主线程以进行UI更新 我一直在阅读有关这方面各种方法的书籍 我理解我的工作可以通过以下方式完成: 幕后工作者 螺纹类 任务类 我应该跳哪一个 更新:使用建议的任务类,我得到了errot,用于跨线程安全,使用以下命令: private void BtnCheckCli
- 幕后工作者
- 螺纹类
- 任务类
private void BtnCheckClick(object sender, EventArgs e)
{
var itm = Task<JDEItemLotAvailability>.Factory.StartNew(() =>
Dal.GetLotAvailabilityF41021(
txtLot.Text,
cmbMcu.SelectedItem.ToString(),
cmbLocn.SelectedItem.ToString())
);
lblDescriptionValue.Text = itm.Result.Description;
lblItemCodeValue.Text = itm.Result.Code;
lblQuantityValue.Text = itm.Result.AvailableQuantity.ToString();
LotFocus(true);
}
private void BtnCheckClick(对象发送方,事件参数e)
{
var itm=Task.Factory.StartNew(()=>
Dal.GetLotAvailabilityF41021(
txtLot.Text,
CMBMU.SelectedItem.ToString(),
cmbLocn.SelectedItem.ToString())
);
lblDescriptionValue.Text=itm.Result.Description;
lblItemCodeValue.Text=itm.Result.Code;
lblQuantityValue.Text=itm.Result.AvailableQuantity.ToString();
LotFocus(真);
}
在上面的exmaple中,我在CMBMUCU控件中遇到异常,而不是txtLot。我使用线程完成了很多项目,但是任务应该更易于使用 下面是如何使用线程进行异步操作的演示 这是将数据返回到ui的类:
public class MyAsyncClass
{
public delegate void NotifyComplete(DataSet data);
public event NotifyComplete NotifyCompleteEvent;
//Starts async thread...
public void Start()
{
System.Threading.Thread t = new System.Threading.Thread(new System.Threading.ThreadStart(DoSomeJob));
t.Start();
}
void DoSomeJob()
{
//just wait 5 sec for nothing special...
System.Threading.Thread.Sleep(5000);
if (NotifyCompleteEvent != null)
{
//TODO: fill your data...
DataSet ds = new System.Data.DataSet();
NotifyCompleteEvent(ds);
}
}
}
下面是ui实现:
MyAsyncClass myClass = null;
private void button2_Click(object sender, EventArgs e)
{
myClass = new MyAsyncClass();
myClass.NotifyCompleteEvent += new MyAsyncClass.NotifyComplete(myClass_NotifyCompleteEvent);
//here I start the job inside working class...
myClass.Start();
}
//here my class is notified from working class when job is completed...
delegate void myClassDelegate(DataSet data);
void myClass_NotifyCompleteEvent(DataSet data)
{
if (this.InvokeRequired)
{
Delegate d = new myClassDelegate(myClass_NotifyCompleteEvent);
this.Invoke(d, new object[] { data });
}
else
{
//TODO: show your data
MessageBox.Show("Data retrieved!");
}
}
我会使用类,它非常容易同步,并且已经提供了对返回对象的支持
var task = Task.Factory.StartNew(
() => GetDatabaseData(someArguments),
TaskCreationOptions.LongRunning);
// Example method
public DataSet GetDatabaseData(object args) { ... }
这会告诉创建并开始一个新任务,并提示如果调度程序使用线程池,则最好不要使用线程池线程。无论如何,您现在可以决定如何同步
例如,为了实现与Gregor Primar的答案中类似的行为,您可以使用方法设置一个continuation,如下所示:
task.ContinueWith(oldTask => ProcessReturnedData(oldTask.Result));
// Example method
public IEnumerable<SomeEntity> ProcessReturnedData(DataSet data) { ... }
有什么东西阻止你跳到.NET4.5吗?async/await使任务处理更干净。我需要在一些旧的或者XP上运行,这是我唯一的障碍…我被限制在一些Windows XP机器上,所以我不能使用.NET 4.5的新功能,所以我认为我将坚持使用任务类。Backgroundworker往往已经过时了?我认为在Windows窗体应用程序中使用Backgroundworker是完全可以的-它是作为Windows窗体组件设计的。但是我发现任务在处理它们的方式上更高级,它们是旨在简化使用的新概念,所以如果你能使用它们,我推荐它。BackgroundWorker可能也是一个选项,例如它支持报告进度,因此,您可以简单地将其挂接到进度条并进行更新-但您在问题中没有提到这方面的需要,而且我认为对于数据库操作来说,这没有多大意义。谢谢,但如果我只运行类似以下内容,它将不会更简单:
var pi=Task.Factory.StartNew(()=>ComputePi(numDigits))。。。控制台写入线(pi.Result)代码>并直接将结果获取到我的ui?毕竟,我最想做的是运行一个方法并将数据库结果返回到我的主线程。对于许多GUI框架来说,这是一件事——您需要在GUI线程(通常是主线程)上进行UI更改(或更改“表单”类)。您的示例在numDigits
变量上创建了一个变量,这可能是一个问题。尝试将其作为参数传递给lambda,而不是直接传递给ComputePi方法:Task.Factory.StartNew(num=>ComputePi(num),numDigits)代码>问题已解决,将其添加到问题中以确保完整性。谢谢
task.Wait(); // Makes current thread wait until the task is comnpleted.
DataSet result = task.Result; // Accessing the result object.