Reputation: 23850
When I run the below code it is supposed fill the ListBox
with each DataRow
's values, but it is filling the ListBox
with single DataRow
's value.
What is the problem and how can I solve it? This is a C# 4.0 WPF application.
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());
}));
}
}
}
Upvotes: 1
Views: 115
Reputation: 1502206
The problem is that you're capturing the drw
variable in your anonymous method. That variable is being updated in the foreach
loop, so by the time your delegates are invoked on the dispatcher thread, you're getting the same value each time. In C# 5, this would be okay (it's such a common error that the language has changed to avoid it) but before C# 5 you need to copy the variable in the loop:
foreach (DataRow drw in dtTemp.Rows)
{
DataRow copy = drw;
this.Dispatcher.BeginInvoke(new Action(delegate()
{
listBox1.Items.Add(copy["Value"].ToString());
}));
}
Or even better, do all the data access in the background thread:
foreach (DataRow drw in dtTemp.Rows)
{
string item = drw["Value"].ToString();
this.Dispatcher.BeginInvoke(new Action(delegate()
{
listBox1.Items.Add(item);
}));
}
Note that the change to C# 5 only affects foreach
- not for
loops.
Also note that your code can be slightly shorted using a lambda expression instead of an anonymous method:
foreach (DataRow drw in dtTemp.Rows)
{
string item = drw["Value"].ToString();
Action action = () => listBox1.Items.Add(item);
this.Dispatcher.BeginInvoke(action);
}
Upvotes: 6
Reputation: 44376
Variable capturing strikes again. (Google: variable capture)
Try creating a temporary variable and passing that to the thread, like this:
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());
}));
}
}
}
Upvotes: 4