//主窗口
    public partial class frmMain : Form
    {
        private System.Windows.Forms.TreeView tvChapterSelector;//初始化语句略
         OpenStoryFile osfOpenStoryFile = new OpenStoryFile();        public frmMain()
        {
            InitializeComponent();
        }        private void frmMain_Load(object sender, EventArgs e)
        {
            osfOpenStoryFile.OpenStoryFileComplete += new OpenStoryFile.OpenStoryFileCompleteHandle(osfOpenStoryFile_OpenStoryFileComplete);
            osfOpenStoryFile.DoOpenStoryFile(@"F:\小说\科幻\回归千年.txt");
        }        void osfOpenStoryFile_OpenStoryFileComplete(System.Collections.ArrayList e)
        {
            for (Int32 I = ConstantVars.GlogbalConst.iZero; I < alStoryChapter.Count; I++)
            {
                tvChapterSelector.Nodes.Add((string)alStoryChapter[I] + string.Empty);//这句报错
                //在该控件上执行的操作正从错误的线程调用。使用 Control.Invoke 或 Control.BeginInvoke 封送到正确的线程才能执行此操作。

            }
        }
    }    //异步打开文件的类
    public class OpenStoryFile
    {
        public delegate void OpenStoryFileCompleteHandle(System.Collections.ArrayList e);        public event OpenStoryFileCompleteHandle OpenStoryFileComplete;
        private event OpenStoryFileCompleteHandle OpenStoryFileCompletePretreat;        System.Windows.Forms.Control ctrlTurnThread;
        System.Threading.Thread thrdOpenFile;
        object objForLock = new object();        string StoryFileToOpen;        public OpenStoryFile()
        {
            ctrlTurnThread = new Control();//这里创建控件应该表示这个控件是在主线程创建的吧?
            this.OpenStoryFileCompletePretreat += new OpenStoryFileCompleteHandle(OpenStoryFile_OpenStoryFileCompletePretreat);
        }        void OpenStoryFile_OpenStoryFileCompletePretreat(OpenStoryFile.OpenStoryFileArgs e)
        {
            if (ctrlTurnThread.InvokeRequired)
            {
                MessageBox.Show("ctrlTurnThread.InvokeRequired");//但是,这句没有执行到
                OpenStoryFileCompleteHandle osfcpT = new OpenStoryFileCompleteHandle(OpenStoryFileCompletePretreat);
                ctrlTurnThread.Invoke(osfcpT, new object[] { e });
            }
            else
            {
                MessageBox.Show("ctrlTurnThread.InvokeRequired Treated");//直接跑这来了。为什么?
                OpenStoryFileComplete(e);
            }
        }        public void DoOpenStoryFile(string StoryFileToOpen)
        {
            this.StoryFileToOpen = StoryFileToOpen;            thrdOpenFile = new System.Threading.Thread(new System.Threading.ThreadStart(OpenStoryFileAsyn));
            thrdOpenFile.Start();
        }        private void OpenStoryFileAsyn()
        {
            lock (objForLock)
            {
                if (System.IO.File.Exists(StoryFileToOpen))
                {
                    try
                    {
                        System.Collections.ArrayList alStoryChapter = new System.Collections.ArrayList();
                        //打开文件并作相应处理后,把内容填充到alStoryChapter
                    }
                    OpenStoryFileCompletePretreat(alStoryChapter);//调用委托
                }
            }
        }
    }

解决方案 »

  1.   

    漏了个catch块。没影响的只是我打漏了。
      

  2.   

    调用InvokeRequired的时候,
    先检查控件的句柄(一种Win32窗口句柄)是否已经创建了,你的情况下IsHandleCreated为假,因为该控件还没有初次显示。
    如果句柄还没有创建,则尝试检查控件的父控件,而你的情况没有父控件(没有执行过Controls.Add( ctrlTurnThread )之类的语句)。
    如果还没有找到,InvokeRequired就直接返回false了。InvokeRequired需要一个窗口句柄来调用API以便知道该窗口所属的线程号,然后比较该线程号和当前线程号,就可以得出需不需要Invoke了。
    该API就是GetWindowThreadProcessId()如果你感兴趣的话
      

  3.   

    在第一次走OpenStoryFile_OpenStoryFileCompletePretreat的时候,控件并没有被其他线程使用,没有涉及到资源同步问题如果这时候,你让线程SEEP一定时间,紧接着走第二次OpenStoryFile_OpenStoryFileCompletePretreat,你会发现InvokeRequired变成TRUE了