填充网格时,跨线程操作无效

时间:2014-02-27 23:01:49

标签: c# multithreading

我正在尝试从匿名类型实例列表中填充网格。我想应用线程,因为这会使我的应用程序在填充结果时冻结。但我不断收到这个错误:

list of anonymous type instances Control 'gridHotelDetails' accessed from a thread other than the thread it was created on. 

我已经标记了发生错误的行。我的代码:

public Thread MyThread { get; private set; }
public string search { get; set; }
public string searchCity { get; set; }
public string searchState { get; set; }

private void crawl()
{
    if (CheckForInternetConnection())
    {
        if (string.IsNullOrEmpty(search) || string.IsNullOrEmpty(search) || string.IsNullOrEmpty(searchCity) || string.IsNullOrWhiteSpace(searchCity) || string.IsNullOrEmpty(searchState) || string.IsNullOrWhiteSpace(searchState))
        {
            MessageBox.Show("Please fill up the search criterias");
        }
        else
        {
            string url = string.Format("http://www.yellowpages.com/{0}/hotels?g={1}&q={2}", searchCity, searchCity, search);
            if (!isURLExist(url))
            {
                MessageBox.Show("No records found. Please try again.");
            }
            else
            {
                Pages htmlDoc = new Pages(url);
                htmlDoc.pageResults();

                string searchUrl = string.Empty;
                for (int ii = 1; ii <= 1; ii++)
                {
                    searchUrl = url + "&page=" + ii;
                    htmlDoc.findHotels(searchUrl);

                    List<string> Name = htmlDoc.Names;
                    List<string> Address = htmlDoc.Address;
                    List<string> City = htmlDoc.City;
                    List<string> State = htmlDoc.State;
                    List<string> Zip = htmlDoc.Zip;
                    List<string> Phone = htmlDoc.Phone;
                    List<string> Website = htmlDoc.Website;

                    var CompleteInformation = Name.Zip(Address, (n, a) => new { Address = a, Name = n })
                        .Zip(City, (p, c) => new { p.Address, p.Name, City = c })
                        .Zip(State, (q, s) => new { q.Address, q.Name, q.City, State = s })
                        .Zip(Zip, (r, z) => new { r.Address, r.Name, r.City, r.State, Zip = z })
                        .Zip(Phone, (t, p) => new { t.Name, t.Address, t.City, t.State, t.Zip, Phone = p })
                        .Zip(Website, (u, w) => new { u.Name, u.Address, u.City, u.State, u.Zip, u.Phone, Website = w })
                        .ToList();

                    int rowCount = gridHotelDetails.Rows.Count;
                    foreach (var detail in CompleteInformation)
                    {
// Error occuring in this line 
                        gridHotelDetails.Rows.Add(rowCount++, detail.Name, detail.Address, detail.City, detail.State, detail.Zip, detail.Phone, detail.Website);  
                    }

                }
            }
            UseWaitCursor = false;
        }
    }
    else
    {
        MessageBox.Show("Internet Connection Not Available");
    }
}

private void btnSearch_Click(object sender, EventArgs e)
{
    search = txtSearch.Text.Trim();
    searchCity = txtCity.Text.Trim();
    searchState = ddState.Text.Trim();

    MyThread = new Thread(new ThreadStart(crawl));
    MyThread.Start();
    gridHotelDetails.Visible = true;
}

为什么会出现此错误?如何解决此错误?

2 个答案:

答案 0 :(得分:1)

您无法从创建的线程以外的线程更改ui控件。请参阅此文章以获取如何完成所需内容的示例:

Trying to change UI control property from different thread using . InvokeRequired

答案 1 :(得分:1)

简短的回答是,当您从非UI线程更新它们时,需要在UI元素上使用Invoke。按钮点击和处理程序通常不在UI线程上。

任何名为InvokeRequired的UI元素都应该有一个属性。如果是这样,则需要使用Invoke传递委托以完成您要在该UI元素上完成的工作。如果它是假的,你可以直接设置属性(因为你在UI线程上)。

所以类似(虽然你会想要从foreach循环中取出这个检查,因为它在执行期间不会改变,你只是浪费周期检查):

if (!gridHotelDetails.InvokeRequired)
{
    gridHotelDetails.Rows.Add(rowCount++, detail.Name, detail.Address, detail.City, detail.State, detail.Zip, detail.Phone, detail.Website);
}
else
{
    gridHotelDetails.Invoke(() =>
    {
        gridHotelDetails.Rows.Add(rowCount++, detail.Name, detail.Address, detail.City, detail.State, detail.Zip, detail.Phone, detail.Website);
    });
}