1

当我运行下面的代码时,它应该ListBox用 eachDataRow的值填充,但它ListBox用 singleDataRow的值填充。

有什么问题,我该如何解决?这是一个 C# 4.0 WPF 应用程序。

    Task.Factory.StartNew(() =>
    {
        myThread();
    });

void myThread()
{
    using (DataTable dtTemp = DbConnection.db_Select_DataTable(srQuery))
    {
        foreach (DataRow drw in dtTemp.Rows)
        {   
            this.Dispatcher.BeginInvoke(new Action(delegate()
            {
                listBox1.Items.Add(drw["Value"].ToString());
            }));
        }
    }
}
4

2 回答 2

6

问题是您正在drw匿名方法中捕获变量。该变量正在foreach循环中更新,因此当您的委托在调度程序线程上被调用时,您每次都会获得相同的值。在 C# 5 中,这是可以的(这是一个常见的错误,语言已经改变以避免它)但在 C# 5 之前,您需要在循环中复制变量:

foreach (DataRow drw in dtTemp.Rows)
{   
    DataRow copy = drw;
    this.Dispatcher.BeginInvoke(new Action(delegate()
    {
        listBox1.Items.Add(copy["Value"].ToString());
    }));
}

或者更好的是,在后台线程中进行所有数据访问:

foreach (DataRow drw in dtTemp.Rows)
{   
    string item = drw["Value"].ToString();
    this.Dispatcher.BeginInvoke(new Action(delegate()
    {
        listBox1.Items.Add(item);
    }));
}

请注意,对 C# 5 的更改影响foreach- 而不是for循环。

另请注意,您的代码可以使用 lambda 表达式而不是匿名方法稍微缩短:

foreach (DataRow drw in dtTemp.Rows)
{   
    string item = drw["Value"].ToString();
    Action action = () => listBox1.Items.Add(item);
    this.Dispatcher.BeginInvoke(action);
}
于 2012-12-31T14:37:44.457 回答
4

变量捕捉再次来袭。(谷歌:变量捕获

尝试创建一个临时变量并将其传递给线程,如下所示:

void myThread()
{
    using (DataTable dtTemp = DbConnection.db_Select_DataTable(srQuery))
    {
        foreach (DataRow drw in dtTemp.Rows)
        {
            DataRow tmp = drw;
            this.Dispatcher.BeginInvoke(new Action(delegate()
            {
                listBox1.Items.Add(tmp["Value"].ToString());
            }));
        }
    }
}
于 2012-12-31T14:36:54.380 回答