我需要写一个日志分析的软件,因为日志文件在大多数都在300MB以上,所以我不得不使用多线程以防止窗体假死。但是我却要通过窗体来显示当前日志分析的状态,我尝试在线程开始时通过一个对象封装新线程开始时所需要使用的数据。在这个对象中有一个Label类型的属性,但是我在新线程中设置Label的Text属性值似乎不太正常。每次调试程序时走到这里就报出“线程间操作无效: 从不是创建控件“lblState”的线程访问它”的异常,郁闷的时以前这样用就很正常,而且现在不使用VS调试状态下也可以正常使用!
下面是窗体的后台代码:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using ParseLogData.ParseLgoBLL;
using ParseLogData.ParseLogDEL;
using System.Threading;
using System.IO;namespace ParseLogData
{
    public partial class ParseData : Form
    {
        public ParseData()
        {
            InitializeComponent();
        }        private void ParseData_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effect = DragDropEffects.Link;
            else
                e.Effect = DragDropEffects.None;
        }        private void ParseData_DragDrop(object sender, DragEventArgs e)
        {
            txtSelectPath.Text = ((System.Array)e.Data.GetData(DataFormats.FileDrop)).GetValue(0).ToString();
            if (!File.Exists(txtSelectPath.Text))
                return;
            StartParseData();
        }        private void btnSelectPath_Click(object sender, EventArgs e)
        {
            if (ofdSelectPath.ShowDialog().ToString() != "OK")
                return;
            txtSelectPath.Text = ofdSelectPath.FileName;
            StartParseData();
        }        private void StartParseData()
        {
            
            if (rbtnEpsLog.Checked)
            {
                ThreadSendDEL tsd = new ThreadSendDEL(txtSelectPath.Text.Trim(), lblState);
                ParseEpsLogBLL pelb = new ParseEpsLogBLL();
                Thread thr = new Thread((new ParseData()).TestSetLblStateText);
                thr.Start(tsd);
            }
            else
            {
                ParseEtermLogBLL pelb = new ParseEtermLogBLL();
            }
        }        public void TestSetLblStateText(object obj)
        {
            ThreadSendDEL th = obj as ThreadSendDEL;
            th.LblState.Text = "正在解析数据,请稍候......";
            
        }
    }
}
//下面是新线程所需要的数据封装对象实体类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Data;namespace ParseLogData.ParseLogDEL
{
    /// <summary>
    /// 向Thread发送的数据实体
    /// </summary>
    public class ThreadSendDEL
    {
        private string filePath;        public string FilePath
        {
            get { return filePath; }
        }
        private Label lblState;        public Label LblState
        {
            get { return lblState; }
        }
        private DataTable dtLogData=new DataTable();        public DataTable DtLogData
        {
            get { return dtLogData; }
        }
        /// <summary>
        /// 要向线程发送的数据
        /// </summary>
        /// <param name="filePath">文件位置</param>
        /// <param name="lblStates">线程处理时状态呈现所要使用的Label控件</param>
        public ThreadSendDEL(string filePath, Label lblState)
        {
            this.filePath = filePath;
            this.lblState = lblState;
            this.dtLogData.Columns.Add("EPSType", typeof(string));
            this.dtLogData.Columns.Add("EPSUser", typeof(string));
            this.dtLogData.Columns.Add("EPSServer",typeof(string));
            this.dtLogData.Columns.Add("EPSPID",typeof(string));
            this.dtLogData.Columns.Add("EPSIP",typeof(string));
            this.dtLogData.Columns.Add("SendData",typeof(string));
            this.dtLogData.Columns.Add("SendDate",typeof(DateTime));
            this.dtLogData.Columns.Add("ReceiveData",typeof(string));
            this.dtLogData.Columns.Add("ReceiveDate",typeof(DateTime));
        }
    }
}

解决方案 »

  1.   

    你在窗体的Load中添加:
    Control.CheckForIllegalCrossThreadCalls = false;
      

  2.   


    “线程间操作无效: 从不是创建控件“lblState”的线程访问它”原因已经很清楚了~~~~~~~~
    上面哪种方法虽然可用。但不安全建议用委托delegate void myDelegate(string s);private void SetLabelText(string s)
    {
       if(label1.InvokeRequired)
       {
          myDelegate d = new myDelegate(SetLabelText);
          this.invoke(d,new object[]{s});
       }
       else
       {
           label1.Text = s;
       }
    }
      

  3.   

    还是那句话,最简单的2楼,最安全的3楼:
    单说委托你可能不太理解其意思,附一个小例子你看看就明白委托怎么用了
    情形:抓网页HTML代码
    在toolStripTextBox1输入要抓的网站,点击按钮抓取,并将网页HTML代码显示在richTextBox1中using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Net;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.IO;
    using System.Threading;
    namespace test
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        private static string str_url = string.Empty;
            public delegate void SetTextHandler(string text); 
            private void toolStripButton1_Click(object sender, EventArgs e)
            {
                if (toolStripTextBox1.Text.Length > 0)
                {
                    str_url = toolStripTextBox1.Text.Trim();
                    ParameterizedThreadStart ParStart = new ParameterizedThreadStart(GetPageSource);   
                    Thread myThread = new Thread(ParStart);
                    //是否背景线程根据自己需要加,加上后理论上不影响界面的操作,就是不卡
                    myThread.IsBackground = true;
                    object o = str_url;   
                    myThread.Start(o);
                    //GetPageSource(toolStripTextBox1.Text.ToString().Trim());
                }
            }        private void GetPageSource(object url)
            {
                //两种抓取网页源码的方法,任选其一即可
                //Uri uri = new Uri(url.ToString());
                //HttpWebRequest hwReq = (HttpWebRequest)WebRequest.Create(uri);
                //HttpWebResponse hwRes = (HttpWebResponse)hwReq.GetResponse();            //hwReq.Method = "Get";            //hwReq.KeepAlive = false;            ////从输入的网站提取HTML源码
                //StreamReader reader = new StreamReader(hwRes.GetResponseStream(), System.Text.Encoding.GetEncoding("GB2312"));
                //settext(reader.ReadToEnd());            try
                {
                    WebClient mywebclient = new WebClient();
                    byte[] pagedata = mywebclient.DownloadData(url.ToString());
                    string pagehtml = "";                //设置编码
                    pagehtml = Encoding.Default.GetString(pagedata);
                    settext(pagehtml);
                }
                catch
                {            }
            }
        
            //委托修改richTextBox1显示,否则会显示线程间操作无效的错误
            private void settext(string text)
            {
                if (richTextBox1.InvokeRequired == true)
                {
                    SetTextHandler set = new SetTextHandler(settext);
                    richTextBox1.Invoke(set, new object[] { text });
                }
                else
                {
                    richTextBox1.Text = text;
                }         }
        
    }
    }
      

  4.   

    嗯,对的用事件委托来处理,我最近也遇到这样的问题,后来是这样解决的
    // 声明事件委托
    delegate void HandleInterfaceUpdateDelegate(string text); 
    HandleInterfaceUpdateDelegate interfaceUpdateHandle;
    //实例化委托对象 
    interfaceUpdateHandle = new HandleInterfaceUpdateDelegate(UpdateText);// 通知委托事件
    this.Invoke(interfaceUpdateHandle, builder.ToString());// 更新UI
    public void UpdateText(string text)
    {
        textBox1.Text += text; 
    }