在线程中访问另一个线程创建的控件

人生导师 2013-05-28 10:39:36
最近一直在论坛上看到很多朋友在使用多线程的时候出现"无法访问另一个线程这样的错误".只要你使用了多线程,出现这样的错误很常见,因为.NET 有它自己的安全性,它规定了不能在一个线程上访问另外一个线程创建的控件,为了解决解决这个问题,我们可以使用委托的回调的机制或获取线程的同步上下文机制来解决.下面就看具体代码实现:
...全文
192 3 打赏 收藏 转发到动态 举报
写回复
用AI写文章
3 条回复
切换为时间正序
请发表友善的回复…
发表回复
人生导师 2013-05-29
  • 打赏
  • 举报
回复
// 捕捉调用线程的同步上下文派生对象 sc = SynchronizationContext.Current;
book_freeboy827 2013-05-28
  • 打赏
  • 举报
回复

this.invoke(new eventhandler(delegate{
      //在这里写
}));
人生导师 2013-05-28
  • 打赏
  • 举报
回复
 public partial class MainForm : Form
    {
        // 定义用来实现异步编程的委托
        private delegate string AsyncMethodCaller(string fileurl);

          // 定义显示状态的委托
        private delegate void ShowStateDelegate(string value);
        private ShowStateDelegate showStateCallback;

        SynchronizationContext sc;
        public MainForm()
        {
            InitializeComponent();
            txbUrl.Text = "http://download.microsoft.com/download/7/0/3/703455ee-a747-4cc8-bd3e-98a615c3aedb/dotNetFx35setup.exe";
            showStateCallback = new ShowStateDelegate(ShowState);
        }

        private void btnDownLoad_Click(object sender, EventArgs e)
        {
            rtbState.Text = "Download............";
            btnDownLoad.Enabled = false;
            if (txbUrl.Text == string.Empty)
            {
                MessageBox.Show("Please input valid download file url");
                return;
            }

            AsyncMethodCaller methodCaller = new AsyncMethodCaller(DownLoadFileSync);
            methodCaller.BeginInvoke(txbUrl.Text.Trim(), GetResult, null);

            // 捕捉调用线程的同步上下文派生对象
            sc = SynchronizationContext.Current;
        }

        // 同步下载文件的方法
        // 该方法会阻塞主线程,使用户无法对界面进行操作
        // 在文件下载完成之前,用户甚至都不能关闭运行的程序。
        private string DownLoadFileSync(string url)
        {
            // Create an instance of the RequestState 
            RequestState requestState = new RequestState();
            try
            {
                // Initialize an HttpWebRequest object
                HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(url);

                // assign HttpWebRequest instance to its request field.
                requestState.request = myHttpWebRequest;
                requestState.response = (HttpWebResponse)myHttpWebRequest.GetResponse();
                requestState.streamResponse = requestState.response.GetResponseStream();
                int readSize = requestState.streamResponse.Read(requestState.BufferRead, 0, requestState.BufferRead.Length);

                while (readSize > 0)
                {
                    requestState.filestream.Write(requestState.BufferRead, 0, readSize);
                    readSize = requestState.streamResponse.Read(requestState.BufferRead, 0, requestState.BufferRead.Length);
                }

                // 执行该方法的线程是线程池线程,该线程不是与创建richTextBox控件的线程不是一个线程
                // 如果不把 CheckForIllegalCrossThreadCalls 设置为false,该程序会出现“不能跨线程访问控件”的异常
                return string.Format("The Length of the File is: {0}", requestState.filestream.Length) + string.Format("\nDownLoad Completely, Download path is: {0}", requestState.savepath);
            }
            catch (Exception e)
            {
                return string.Format("Exception occurs in DownLoadFileSync method, Error Message is:{0}", e.Message);
            }
            finally
            {
                requestState.response.Close();
                requestState.filestream.Close();
            }
        }

        // 异步操作完成时执行的方法
        private void GetResult(IAsyncResult result)
        {
            AsyncMethodCaller caller = (AsyncMethodCaller)((AsyncResult)result).AsyncDelegate;
            // 调用EndInvoke去等待异步调用完成并且获得返回值
            // 如果异步调用尚未完成,则 EndInvoke 会一直阻止调用线程,直到异步调用完成
            string returnstring = caller.EndInvoke(result);

            // 通过获得GUI线程的同步上下文的派生对象,
            // 然后调用Post方法来使更新GUI操作方法由GUI 线程去执行
            sc.Post(ShowState,returnstring);      
        }

        // 显示结果到richTextBox
        // 因为该方法是由GUI线程执行的,所以当然就可以访问窗体控件了
        private void ShowState(object result)
        {
            rtbState.Text = result.ToString();
            btnDownLoad.Enabled = true;
        }
    }
大家可以参考代码中的代码来解决你们碰到的问题,希望对大家有所帮助,更多内容可以看 :http://blog.csdn.net/lizhi3186575/article/details/8909950

110,534

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧