【问题标题】:How can I correct the error "accessed from a thread other than the thread it was created on"?如何更正错误“从创建它的线程以外的线程访问”?
【发布时间】:2009-05-29 08:48:59
【问题描述】:

下面的代码给了我下面的错误。我想我需要 "InvokeRequired" 。但是不明白怎么用?

跨线程操作无效:控件“listBox1”从创建它的线程以外的线程访问。

代码:

using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;

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

        protected static DataSet dataset = null;
        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            SimulationFrameWork.MCSDirector run = new SimulationFrameWork.MCSDirector();
            DataSet ds = run.Get();

            if (ds.Tables[0].Rows.Count > 0)
            {
                for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
                {
                    if (ds.Tables[0].Rows[i]["result"].ToString() == "0")
                    {
                       dataset = run.Get(int.Parse(ds.Tables[0].Rows[i]["ID"].ToString()));
                       WorkerObject worker = 
                         new WorkerObject(
                           int.Parse(dataset.Tables[0].Rows[i]["ID"].ToString()),
                           int.Parse(dataset.Tables[0].Rows[i]["Iteration"].ToString()),
                           listBox1, timer1);
                       Thread thread1 = new Thread(new ThreadStart(worker.start));
                       thread1.Start();
                    }
                }
            }
        }
    }

    public class WorkerObject
    {
        private int id;
        private int nmax;
        private ListBox list1;
        private System.Windows.Forms.Timer timer1;

        public WorkerObject(int _id, int _nmax, ListBox _list1, 
                            System.Windows.Forms.Timer _timer1)
        {
            id = _id;
            nmax = _nmax;
            list1 = _list1;
            timer1 = _timer1;
        }
        public void start()
        {
            timer1.Stop();
            int i, idaire, j;
            double pi = 0.0, x, y;

            Random rnd = new Random();
            for (i = 0; i < 100; i++)
            {
                idaire = 0;
                for (j = 0; j < nmax; j++)
                {
                    x = rnd.Next(1, 10000) / (double)10000;
                    y = rnd.Next(1, 10000) / (double)10000;
                    if (Math.Pow(x, 2) + Math.Pow(y, 2) <= 1.0)
                        idaire += 1;
                }
                pi = 4 * (double)idaire / (double)nmax;
                nmax *= 10;

                list1.Items.Add(
                  "Iterasyon:" + 
                  nmax.ToString() + 
                  " ----->" + 
                  pi.ToString() + 
                  "\n");
                System.Threading.Thread.Sleep(100);
            }
            SimulationFrameWork.MCSDirector run = new SimulationFrameWork.MCSDirector();
            run.Update(id, pi);
            list1.Items.Add("\n\n islem bitti...");
        }
    }
}

【问题讨论】:

标签: c# .net multithreading


【解决方案1】:

这应该能让你绕过它

private delegate void stringDelegate(string s);
private void AddItem(string s)
{
    if (list1.InvokeRequired)
    {
        stringDelegate sd = new stringDelegate(AddItem);
        this.Invoke(sd, new object[] { s });
    }
    else
    {
        list1.Items.Add(s);
    }
}

只需调用 AddItem ,如果需要,这将使用委托调用添加,否则它将直接将项目添加到框中。

单次

【讨论】:

  • 刚刚注意到你的代码在 (int i = 0; i " + pi.ToString() + "\n");就在 (int i = 0; i
  • 没有必要声明额外的代表;你可以使用 MethodInvoker 来做到这一点...
  • 有什么方法简单的方法:DoWork、ProgressChanged、RunWorkerCompleted
  • @MarcGravell 但在 .NET 4 中仅当委托方法不带参数时:(
  • @MatthewLock 将其映射到 anon-method/lambda - 等等:没有参数。调用((MethodInvoker)() => AddItem(s));
【解决方案2】:

只需将添加到列表框中的文本封装到另一个方法中:

private void timer1_Tick(object sender, EventArgs e)
{
   // ...
   AddTextToListBox("\n\n işlem bitti...");
}

private void AddTextToListBox(string text)
{
   if(list1.InvokeRequired)
   {
      list1.Invoke(new MethodInvoker(AddTextToListBox), new object[] { text }); 
      return;
   }

   list1.Items.Add(text);
}

【讨论】:

  • 根据此链接:msdn.microsoft.com/en-us/library/… 您不能在 .NET 4 中将 MethodInvoker 委托与带参数的方法一起使用。如果您正在寻找此问题的答案,请查看下面的 OneSHOT 解决方案。跨度>
【解决方案3】:

也可以使用 lambda 表示法。所以,而不是:

formControl.Field = newValue; //Causes error

试试:

Invoke(new Action(() =>
{
    formControl.Field = newValue; //No error
}));

【讨论】:

    【解决方案4】:

    在启动线程之前添加此代码:

    //kolay gelsin kardeş )
    CheckForIllegalCrossThreadCalls = false;
    thread1.Start();
    

    【讨论】:

    • 这不是一个好主意。这将防止确定性异常以换取不可预测和惊人的错误。
    猜你喜欢
    • 2014-09-19
    • 1970-01-01
    • 1970-01-01
    • 2011-01-15
    • 2013-07-06
    • 1970-01-01
    • 2016-05-21
    相关资源
    最近更新 更多