从另一个线程获取控件的属性

3

我想从我的表单中的 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
}

有人能提供一个最简单和最容易的方法来做到这一点吗?

可能重复:http://stackoverflow.com/questions/6092519/winforms-thread-safe-control-access - zmbq
如果您可以使用BackgroundWorker,那么您表单中的每个控件都已经可读了... - Marco
请展示您正在使用的代码... - Marco
ListView.CheckedItems 对我来说没有意义。这是一个打字错误吗(你是不是想说 ListView1.CheckedItems 或类似的东西)? - Rob P.
2个回答

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.) 在表单加载时 - 在主线程上执行代码(它可以正常工作),然后在backgroundWorker线程上执行代码(它会失败)。

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是一种常见的模式,您将经常使用它(这就是为什么它包含在所有控件中的原因)。如果您在各个地方都这样做,您可以聪明地将其全部包装起来 - 如此描述:自动化InvokeRequired代码模式


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;
        }
    }
}

不过,你的问题很笼统。如果你能分享更多细节,可能会有更简单或更好的解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接