从另一个线程获取Control的属性

时间:2012-05-13 13:01:49

标签: c# .net vb.net winforms multithreading

我希望从我的表单中的BackgroundWorker获取控件的属性:

foreach (ListViewItem i in ListView.CheckedItems) { //error: Cross-thread operation not valid: Control 'ListView' accessed from a thread other than the thread it was created on.
    //do something with i
}

有人能建议最简单,最简单的方法吗?

2 个答案:

答案 0 :(得分:2)

让我再次尝试......

1。)将ListView拖到窗体

2。)将BackgroundWorker拖到窗体

3。)创建一个方法,迭代ListViewItem集合

private void LoopThroughListItems()
{
    foreach (ListViewItem i in listView1.CheckedItems)
        DoSomething(); 

}

4.。)添加代码以在BackgroundWorker的DoWork事件中调用LoopThroughListItems()

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    LoopThroughListItems();
}

5.。)在你的表单加载 - 执行主线程上的代码(它工作)然后在backgroundWorkder线程上执行(它失败)

private void Form1_Load(object sender, EventArgs e)
{
    // Try it on the UI Thread - It works
    LoopThroughListItems();

    // Try it on a Background Thread - It fails
    backgroundWorker1.RunWorkerAsync();

}

6。)修改您的代码以使用IsInvokeRequired / Invoke

private void LoopThroughListItems()
{

    // InvokeRequired == True when executed by non-UI thread
    if (listView1.InvokeRequired)
    {
        // This will re-call LoopThroughListItems - on the UI Thread
        listView1.Invoke(new Action(LoopThroughListItems));
        return;
    }

    foreach (ListViewItem i in listView1.CheckedItems)
        DoSomething(); 
}

7.。)再次运行应用程序 - 现在它可以在UI线程和非UI线程上运行。

解决问题。检查IsInvokeRequired / Invoking是一个常用的模式,你会习惯使用它(这就是为什么它包含在所有控件中)。如果你在整个地方都这样做,你可以做一些聪明的事情并将其全部包装起来 - 如下所述:Automating the InvokeRequired code pattern

答案 1 :(得分:1)

尝试这样的事情:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void OnClick(object sender, EventArgs e)
        {
            backgroundWorker1.RunWorkerAsync();
        }

        private void OnDoWork(object sender, DoWorkEventArgs e)
        {
            foreach (ListViewItem i in GetItems(listView1))
            {
                DoSomething(i);
            }
        }

        private IEnumerable<ListViewItem> GetItems(ListView listView)
        {
            if (InvokeRequired)
            {
                var func = new Func<ListView, IEnumerable<ListViewItem>>(GetItems);
                return (IEnumerable<ListViewItem>)Invoke(func, new[] { listView });
            }
            // Create a defensive copy to avoid iterating outsite UI thread
            return listView.CheckedItems.OfType<ListViewItem>().ToList();
        }

        private void DoSomething(ListViewItem item)
        {
            if (InvokeRequired)
            {
                var action = new Action<ListViewItem>(DoSomething);
                Invoke(action, new[] { item });
                return;
            }
            // Do whatever you want with i
            item.Checked = false;
        }
    }
}

然而,你的问题非常普遍。如果您分享更多详细信息,可能会有更简单或更好的解决方案。