异步任务问题 - 对表单的跨线程访问

时间:2012-06-03 08:35:46

标签: c# task-parallel-library async-ctp

已简化的7个步骤:

  1. [MainForm]用户点击btnAdd按钮
  2. 将显示AddForm
  3. [AddForm]点击了btnCreate
  4. 在btnCreate_Click中我们使用awaiter运行AddProductProcess *我们会在点击后立即关闭AddForm * 并显示MainForm
  5. 在AddProductProcess中,我们使用awaiter运行AddProduct
  6. 我们运行AddProduct,它将为我们完成漫长的过程并填充Application-Level静态集合:ProductCollection
  7. [MainForm]完成Process AddProduct后,我们将在lstProducts ListBox中显示已添加的产品项。

  8. 5段代码:

    private void btnAddProduct_Click(object sender, EventArgs e)
    {
        FormAddProduct fap = new FormAddProduct(SelCol);
        fap.ShowDialog();
    }
    
    private async void btnCreate_Click(object sender, EventArgs e)
    {
        string stProduct = txtProductName.Text;
    
        await ProductCollection.AddProductProcess(stProduct);
        this.Close();
        MainForm.Show();
    }           
    
    public async Task AddProductProcess(string pName)
    {
        await Task.Factory.StartNew(() => AddProduct(pName));
        // This would be our heavy process
    }   
    
    public void AddProduct(string pName)
    {
        ProductItem p =  new ProductItem();
        p.Name = pName ;
        p.Position = Count;
        p.GetInfo(); // and some similar heavy methods are inside this
        //ProductCollection.Add(p);
    }
    
    public void Add(Product product)
    {
        MainForm.lstProduct.Add(product.Name);
    }
    

    “MainForm.lstProduct.Add”导致invalid cross-thread operation错误

    我需要在其上添加一个任务完成通知,因此可以以正确的方式将结果添加到ListBox 你能帮我实现一下吗?

    我应该将这行代码传递给在任务完成后立即执行的代码。

    ProductCollection.Add(P);

    对这段代码和主题的任何想法表示赞赏,

1 个答案:

答案 0 :(得分:2)

你在某些地方使用async / await模式,但不是重要的地方......

public async Task AddProductProcess(string pName)
{
    await Task.Factory.StartNew(() =>
        AddProduct(pName));
}   

public void AddProduct(string pName)  // not async
{
    ...
    ProductCollection.Add(p);
}


public void Add(Product product)  // not async
{
    MainForm.lstProduct.Add(product.Name);
}

最后一个方法只在一个Task上运行,所以它是一个'正常'的交叉线程错误。您可以使用MainForm.Invoke(...)以正常方式解决它,但您也可以删除所有async和await关键字。

要正确使用async / await,您必须将其更改为:

public async Task AddProductProcess(string pName)
{
    await AddProduct(pName);
}   

public async void AddProduct(string pName)  
{
    ProductItem p =  new ProductItem();
    p.Name = pName ;
    p.Position = Count;
    await p.GetInfo();    // assuming this is doing the heavy work, make async
    ProductCollection.Add(p);
}