当我运行以下代码时,我们应该在每个ListBox
的值中填充DataRow
,但它会使ListBox
填充DataRow
个值。
问题是什么?如何解决?这是一个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());
}));
}
}
}
答案 0 :(得分: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);
}
答案 1 :(得分:4)
变量捕获再次发生。 (Google:variable capture)
尝试创建一个临时变量并将其传递给线程,如下所示:
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());
}));
}
}
}