Task.StartNew 在运行时持有主线程

e4r*_*dog 1 .net c# multithreading winforms

在此代码运行时,我无法在 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();
Run Code Online (Sandbox Code Playgroud)

我尝试评论对 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();
});
Run Code Online (Sandbox Code Playgroud)

但当然我又在搞乱用户界面了......表单冻结消失了,但是当任务完成时发生了异常

Jon*_*eet 5

这里有两个问题。

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

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

lblDescriptionValue.Text = itm.Result.Description;
Run Code Online (Sandbox Code Playgroud)

对该itm.Result属性的访问将被阻止,直到任务完成。您不想这样做 - 这次是在UI 线程中 - 因为正如您所观察到的那样,这会冻结您的 UI。

如果您使用的是 C# 5 和 .NET 4.5,您可以尝试使用新的异步功能 - 这可能会让您更轻松地做您想做的事。

如果您不能使用 .NET 4.5(或 .NET 4 的异步目标包),您应该使用它Task.ContinueWith来告诉Task您在完成后要做什么。

编辑:我怀疑你想要这样的东西:

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());
Run Code Online (Sandbox Code Playgroud)