private void btnNext_Click(object sender, EventArgs e)
        {
            try
            {
                var emptyDelegate = new EmptyDelegate(Update);
                emptyDelegate.BeginInvoke(null, null);
            }
            catch (Exception ex)
            {
                lblMessage.Text = ex.Message;
            }
        }        void Update()
        {
            var i = lstUser.SelectedIndex;
            while (i + 1 < lstUser.Items.Count - 1)
            {
                lstUser.SelectedIndex = i + 1;
                System.Threading.Thread.Sleep(2000);
                btnLogin_Click(null, null);
                System.Threading.Thread.Sleep(2000);
                btnBack_Click(null, null);
                System.Threading.Thread.Sleep(2000);
                i = i + 1;
            }
        }我想明一个线程,想来更新界面,一开始我是在单线程中的,但这样界面会卡死
现在我开多一个线程提示:线程间操作无效: 从不是创建控件“lstUser”的线程访问它。 谢谢正确写法应该是怎样,谢谢

解决方案 »

  1.   

    把 btnLogin_Click(null, null);和btnBack_Click(null, null);替换为下面的形式:            this.Invoke(new MethodInfo(delegate { 
                    btnLogin_Click(null, null);
                }));
                this.Invoke(new MethodInfo(delegate { 
                    btnBack_Click(null, null);
                }));
      

  2.   

    sorry,上面的MethodInfo应该替换为MethodInvoker
      

  3.   

    错误提示说明得横清楚啊,委托.BeginInvoke()相当于开了一个新线程,新线程调用主线程创建的控件一般都会有错误提示,楼上的代码写的对,this.invoke使用主线程执行操作
      

  4.   

    借贵宝地,求达人推荐能支持下载目录的开源FTP组件!!!!!!!
      

  5.   

    在所启动的的线程方法里最前面加入这么一句话
    CheckForIllegalCrossThreadCalls = false;
    要记得前面加入using System.Threading;
    肯定行的!我有过这问题。
      

  6.   

    using System.Threading;
    //在你的线程方法里的第一句写上
    CheckForIllegalCrossThreadCalls = false;
      

  7.   


            void Update()
            {
                var i = (int)this.Invoke(new Func<int>(() =>
                {
                    return lstUser.SelectedIndex;
                }));            while (i <= (int)this.Invoke(new Func<int>(() =>
                {
                    return lstUser.Items.Count - 1;
                })))
                {
                    this.Invoke(new Action(() =>
                    {
                        lstUser.SelectedIndex = i;
                    }));                System.Threading.Thread.Sleep(3000);
                    this.Invoke(new MethodInvoker(delegate
                    {
                        btnLogin_Click(null, null);
                    }));
                    System.Threading.Thread.Sleep(3000);
                    this.Invoke(new MethodInvoker(delegate
                    {
                        btnBonus_Click(null, null);
                    }));
                    System.Threading.Thread.Sleep(3000);
                    i = i + 1;
                }
            }这个是我改写的,但感觉写的不好
    怎么写更好更科学呢
      

  8.   

            private void btnNext_Click(object sender, EventArgs e)
            {
                try
                {
                    Thread th = new Thread(DoUpdate);
                    th.Start();
                }
                catch (Exception ex)
                {
                    lblMessage.Text = ex.Message;
                }
            }        void DoUpdate()
            {
                this.Invoke(new Action(Update));
            }        void Update()
            {
                var i = lstUser.SelectedIndex;
                while (i + 1 < lstUser.Items.Count - 1)
                {
                    lstUser.SelectedIndex = i + 1;
                    System.Threading.Thread.Sleep(2000);
                    btnLogin_Click(null, null);
                    System.Threading.Thread.Sleep(2000);
                    btnBack_Click(null, null);
                    System.Threading.Thread.Sleep(2000);
                    i = i + 1;
                }
            }
    用这样的方式可能会好点。
      

  9.   


            private void btnNext_Click(object sender, EventArgs e)
            {            try
                {
                    var emptyDelegate = new EmptyDelegate(Update2);
                    emptyDelegate.BeginInvoke(null, null);
                }
                catch (Exception ex)
                {
                    lblMessage.Text = ex.Message;
                }
            }        void Update2()
            {
                if (this.InvokeRequired)
                {
                    this.Invoke(new Action(Update2));
                }
                else
                {
                    var i = lstUser.SelectedIndex;                while (i <= lstUser.Items.Count - 1)
                    {
                        lstUser.SelectedIndex = i;                    System.Threading.Thread.Sleep(3000);
                        btnLogin_Click(null, null);
                        System.Threading.Thread.Sleep(3000);
                        btnBonus_Click(null, null);                    System.Threading.Thread.Sleep(3000);
                        i = i + 1;
                    }
                }
            }我参照网上的写法,但这样会卡死主线程
      

  10.   

    恩,sorry,一时大意了。
    因为invoke后就是主线程了。
    在invoke的函数里面Sleep或是做其他操作自然会阻塞主线程。只有在操作控件的时候一句一句的invoke向你上面那么写,如果btnLogin_Click里面还有Sleep的话依然阻塞主线程,还得写invoke
      

  11.   

    有个简单的方式解决这个问题
    你可以在Form的构造函数中写:        public Form()
            {
                InitializeComponent();
                CheckForIllegalCrossThreadCalls = false;//不捕捉跨线程异常
            }
    然后直接开线程去调用方法就可以了:        private void btnNext_Click(object sender, EventArgs e)
            {
                try
                {
                    Thread th = new Thread(Update);
                    th.Start();
                }
                catch (Exception ex)
                {
                    lblMessage.Text = ex.Message;
                }
            }        void Update()
            {
                var i = lstUser.SelectedIndex;
                while (i + 1 < lstUser.Items.Count - 1)
                {
                    lstUser.SelectedIndex = i + 1;
                    System.Threading.Thread.Sleep(2000);
                    btnLogin_Click(null, null);
                    System.Threading.Thread.Sleep(2000);
                    btnBack_Click(null, null);
                    System.Threading.Thread.Sleep(2000);
                    i = i + 1;
                }
            }不过不太推荐使用这种方式。
      

  12.   

    winform程序的主线程(UI线程)中有一个消息泵,所有的windows消息(包括鼠标、键盘等交互输入)都是靠这个消息泵分送到对应的处理程序。在主线程中调用Thread.Sleep会阻塞线程,消息泵不工作,界面就没有反应了。
    简单的一个方法是用循环代替Thread.Sleep: private void btnNext_Click(object sender, EventArgs e)
    {
    try
    {
    Update(); // 在主线程上执行,就可以省略跨线程调要用control.Invoke这种形式
    }
    catch (Exception ex)
    {
    lblMessage.Text = ex.Message;
    }
    } void Update()
    {
    var i = lstUser.SelectedIndex;
    while (i <= lstUser.Items.Count - 1)
    {
    lstUser.SelectedIndex = i;
    Wait(2000);
    btnLogin_Click(null, null);
    Wait(2000);
    btnBack_Click(null, null);
    Wait(2000);
    i = i + 1;
    }
    } void Wait(int timeout)
    {
    var tEnd = DateTime.Now + TimeSpan.FromMilliseconds(timeout);
    // 让消息泵继续工作,直到结束时间
    while (DateTime.Now < tEnd)
    Application.DoEvents(); 
    }上面这种方式只是比较简便,但不一定是好的做法。好的做法还是你在7楼写的那种,每次跨线程访问UI控件时都调用Invoke方法。
    如果嫌麻烦的话,可以写个扩展方法类让简化调用语句: public static class ControlInvokeExtensions
    {
    public static TResult Invoke<TControl, TResult>(this TControl control, Func<TControl, TResult> func) where TControl : Control
    {
    return (TResult)control.Invoke(new Func<TResult>(()=>func(control)));
    } public static void Invoke<TControl>(this TControl control, Action<TControl> action) where TControl : Control
    {
    control.Invoke(new MethodInvoker(() => action(control)));
    }
    }调用时就比较方便了,代码跟7楼是等效的: private void btnNext_Click(object sender, EventArgs e)
    {
    try
    {
    var emptyDelegate = new EmptyDelegate(Update);
    emptyDelegate.BeginInvoke(null, null);
    }
    catch (Exception ex)
    {
    lblMessage.Text = ex.Message;
    }
    } void Update()
    {
    var i = lstUser.Invoke(x => x.SelectedIndex);

    while (i <= lstUser.Invoke(x => x.Items.Count -1))
    {
    lstUser.Invoke(x => x.SelectedIndex = i);
    System.Threading.Thread.Sleep(3000);
    this.Invoke(x=>btnLogin_Click(null, null));
    System.Threading.Thread.Sleep(3000);
    this.Invoke(x=>btnBonus_Click(null, null));
    System.Threading.Thread.Sleep(3000);
    i = i + 1;
    }
    }
      

  13.   

    跨线程访问控件。
    用 Invoke 函数
     
      

  14.   

    你跨线程了你可以这样。  delegate void SetValueHandler(string key,string value);
            SetValueHandler svh;
            private void Set()
            {
                svh = new SetValueHandler(SetControlValue);
                svh.Invoke("label1", "test1");
                svh.Invoke("label2", "test2");
            }        private void SetControlValue(string key, string value)
            {
                
               // Control control = this.Controls.Find(key, true)[0];
                此处判断下 存不存在控件。
                if (control.InvokeRequired)
                {
                    control.Invoke(svh, new object[] { key, value });
                }
                else
                {
                    control.Text = value; 
                }  
            }