C# Task.StartNew在运行时保留主线程

C# Task.StartNew在运行时保留主线程,c#,.net,winforms,multithreading,C#,.net,Winforms,Multithreading,运行此代码时,我无法在UI中移动或执行任何操作: var a = txtLot.Text; var b = cmbMcu.SelectedItem.ToString(); var c = cmbLocn.SelectedItem.ToString(); var itm = Task<JDEItemLotAvailability> .Factory.StartNew(() => { btnCheck.BackColor = Color.Red;

运行此代码时,我无法在UI中移动或执行任何操作:

var a = txtLot.Text;
var b = cmbMcu.SelectedItem.ToString();
var c = cmbLocn.SelectedItem.ToString();

var itm = Task<JDEItemLotAvailability>
.Factory.StartNew(() =>
{
        btnCheck.BackColor = Color.Red;
        var ret = Dal.GetLotAvailabilityF41021(a, b, c);
        btnCheck.BackColor = Color.Transparent;
        return ret;
}
    );
lblDescriptionValue.Text = itm.Result.Description;
lblItemCodeValue.Text = itm.Result.Code;
lblQuantityValue.Text = itm.Result.AvailableQuantity.ToString();
var a=txtLot.Text;
var b=cmbcu.SelectedItem.ToString();
var c=cmbLocn.SelectedItem.ToString();
var itm=任务
.Factory.StartNew(()=>
{
btnCheck.BackColor=Color.Red;
var ret=Dal.GetLotAvailabilityF41021(a、b、c);
btnCheck.BackColor=Color.Transparent;
返回ret;
}
);
lblDescriptionValue.Text=itm.Result.Description;
lblItemCodeValue.Text=itm.Result.Code;
lblQuantityValue.Text=itm.Result.AvailableQuantity.ToString();
我试着对Dal方法的调用进行注释,并将thread.sleep(5000)放在上面,但我仍然无法移动表单

编辑:也许我使用了错误的方法来获取结果

更新:

在第一次回答(约翰的)后,我尝试了以下方法:

var a = txtLot.Text;
var b = cmbMcu.SelectedItem.ToString();
var c = cmbLocn.SelectedItem.ToString();

var itm = Task<JDEItemLotAvailability>
.Factory.StartNew(() =>
{
        btnCheck.BackColor = Color.Red;
        var ret = Dal.GetLotAvailabilityF41021(a, b, c);
        btnCheck.BackColor = Color.Transparent;
        return ret;
}
    ).ContinueWith(itm =>
{
lblDescriptionValue.Text = itm.Result.Description;
lblItemCodeValue.Text = itm.Result.Code;
lblQuantityValue.Text = itm.Result.AvailableQuantity.ToString();
});
var a=txtLot.Text;
var b=cmbcu.SelectedItem.ToString();
var c=cmbLocn.SelectedItem.ToString();
var itm=任务
.Factory.StartNew(()=>
{
btnCheck.BackColor=Color.Red;
var ret=Dal.GetLotAvailabilityF41021(a、b、c);
btnCheck.BackColor=Color.Transparent;
返回ret;
}
).ContinueWith(itm=>
{
lblDescriptionValue.Text=itm.Result.Description;
lblItemCodeValue.Text=itm.Result.Code;
lblQuantityValue.Text=itm.Result.AvailableQuantity.ToString();
});

当然,我又弄乱了用户界面……表单冻结消失了,但当任务完成时,异常发生了。

这里有两个问题

首先,您的代码试图从几乎可以肯定是不同的线程(即,在任务内,可能在线程池线程中执行)访问UI线程。你不应该那样做

其次,您在这里阻塞了UI线程:

lblDescriptionValue.Text = itm.Result.Description;
itm.Result
属性的访问将被阻止,直到任务完成。你不想这样做——这次是在UI线程中——正如你所观察到的那样,那样会冻结你的UI

如果您使用的是C#5和.NET4.5,那么您可以尝试使用新的异步特性——这可能会使您更容易实现所需的功能

如果你不能使用.NET 4.5(或.NET 4的异步目标包),你应该使用
Task.ContinueWith
告诉
任务完成后你想做什么

编辑:我想你想要的是:

var a = txtLot.Text;
var b = cmbMcu.SelectedItem.ToString();
var c = cmbLocn.SelectedItem.ToString();

btnCheck.BackColor = Color.Red;
var task = Task.Factory.StartNew(() => Dal.GetLotAvailabilityF41021(a, b, c));
task.ContinueWith(t =>
{
    btnCheck.BackColor = Color.Transparent;
    lblDescriptionValue.Text = t.Result.Description;
    lblItemCodeValue.Text = t.Result.Code;
    lblQuantityValue.Text = t.Result.AvailableQuantity.ToString();
}, TaskScheduler.FromCurrentSynchronizationContext());

这里有两个问题

首先,您的代码试图从几乎可以肯定是不同的线程(即,在任务内,可能在线程池线程中执行)访问UI线程。你不应该那样做

其次,您在这里阻塞了UI线程:

lblDescriptionValue.Text = itm.Result.Description;
itm.Result
属性的访问将被阻止,直到任务完成。你不想这样做——这次是在UI线程中——正如你所观察到的那样,那样会冻结你的UI

如果您使用的是C#5和.NET4.5,那么您可以尝试使用新的异步特性——这可能会使您更容易实现所需的功能

如果你不能使用.NET 4.5(或.NET 4的异步目标包),你应该使用
Task.ContinueWith
告诉
任务完成后你想做什么

编辑:我想你想要的是:

var a = txtLot.Text;
var b = cmbMcu.SelectedItem.ToString();
var c = cmbLocn.SelectedItem.ToString();

btnCheck.BackColor = Color.Red;
var task = Task.Factory.StartNew(() => Dal.GetLotAvailabilityF41021(a, b, c));
task.ContinueWith(t =>
{
    btnCheck.BackColor = Color.Transparent;
    lblDescriptionValue.Text = t.Result.Description;
    lblItemCodeValue.Text = t.Result.Code;
    lblQuantityValue.Text = t.Result.AvailableQuantity.ToString();
}, TaskScheduler.FromCurrentSynchronizationContext());

我明白了,我不能使用4.5,因为我需要应用程序在一些XP机器上运行,所以我必须坚持使用任务类。您能告诉我更多关于如何从代码中删除任何ui元素并使用continuewith的信息吗?我试图使用它,但仍有错误。。(我正在用第二个tryWell更新epost,你要做的第一件事是将背景颜色设置为红色-所以在开始任务之前就这样做。然后你可以在任务完成后将其设置为透明。我将用一些示例代码进行编辑。谢谢,如果你能展示我将如何使用ContinueWith(我的意思是结果)。谢谢!@e4rthdog:请参阅我的编辑。但是,如果您可以使用.NET 4异步目标包,这会简单得多。它按预期工作,john。但是在您编写它之前,我尝试了相同的方法,但没有TaskScheduler。FromCurrentSynchronizationContext()我得到了一个跨线程的例外。另外,我刚刚看到了异步目标包,我不明白为什么像这样有用的东西没有出现在头条新闻中……或者可能是这样,我是一个太多的noob:)我明白了,我不能使用4.5,因为我需要应用程序在一些XP机器上运行,所以我必须坚持使用任务类。你能告诉我更多关于如何从代码中删除任何ui元素并使用continuewith的信息吗?我尝试使用它,但仍然会出错。。(我正在用第二个tryWell更新epost,你要做的第一件事是将背景颜色设置为红色-所以在开始任务之前就这样做。然后你可以在任务完成后将其设置为透明。我将用一些示例代码进行编辑。谢谢,如果你能展示我将如何使用ContinueWith(我的意思是结果)。谢谢!@e4rthdog:请参阅我的编辑。但是,如果您可以使用.NET 4异步目标包,这会简单得多。它按预期工作,john。但是在您编写它之前,我尝试了相同的方法,但没有TaskScheduler。FromCurrentSynchronizationContext()我得到了一个跨线程的例外。另外,我刚刚看到了异步目标包,我不明白为什么像这样有用的东西没有出现在头条新闻中……或者可能是这样,我是一个太多的noob:)