1

以下のコードを実行するListBoxと、それぞれDataRowの値で埋められるはずですが、ListBox単一DataRowの値で埋められています。

問題は何ですか?どうすれば解決できますか?これはC#4.0WPFアプリケーションです。

    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への変更は、ループではなく、影響するだけであることに注意してください。foreachfor

また、匿名メソッドの代わりにラムダ式を使用すると、コードをわずかに短縮できることに注意してください。

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

可変キャプチャストライクが再び発生します。(Google:変数キャプチャ

次のように、一時変数を作成してスレッドに渡してみてください。

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 に答える