访问GUI元素没有按预期工作

本文关键字:工作 GUI 元素 访问 | 更新日期: 2023-09-27 17:50:02

当我运行下面的代码时,它应该用每个DataRow的值填充ListBox,但它正在用单个DataRow的值填充ListBox

问题是什么,我该如何解决它?这是一个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());
            }));
        }
    }
}

访问GUI元素没有按预期工作

问题是您在匿名方法中捕获了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);
}

变量捕获再次发生。(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());
            }));
        }
    }
}