本帖最后由 conmajia 于 2012-08-05 01:30:52 编辑

解决方案 »

  1.   

    这位兄台,好象你的代码很复杂。我前几天写了一下,表述力不佳,仅贴代码。    public class ThreadRunCode
        {
            public Thread th;
            public bool bExceptRun=true;//是否结束线程,这个可以在外控制线程
            public bool bSleep=true;//本次线程的时间片是否执行事件。
            private System.Windows.Forms.Form frm;        public delegate void ThreadRunMthod();
            public event ThreadRunMthod threadRunMthod;        public void RunThread() 
            {
                th = new Thread(new ThreadStart(RunThreadCode));
                th.Start();
            }
            private void RunThreadCode() 
            {
                do
                {
                    if (bSleep) 
                    {
                        continue;
                    }
                    this.frm.Invoke(threadRunMthod);
                } while (bExceptRun);
            }
        }在Form中调用举例:     public int i;
         //others code
         ThreadRunCode threadRunCode=new ThreadRunCode(this);
         threadRunCode.threadRunMthod += new ThreadRunMthod(ThreadRunCode_threadRunMthod);
         threadRunCode.bSleep=false;
         threadRunCode.RunThread();
        //others code
          void ThreadRunCode_threadRunMthod()
          {
                textBox1.text=(i++).ToString();
          }    这样写是不是也可以实现多线程,其实我在想,多线程同一时刻尽量少,应该他存在的时候才启动。比如你说的例子,我认为在要修改界面的时候再建一个线珵,修改完后就终止线程,再改变的时候再建一个。
         
      

  2.   

    远离反射,通常更能够保证性能。而且以下方法更加直观和方便。在你的工程中的扩展方法类中写下一个SafeCall方法:using System;
    using System.Windows.Forms;namespace WindowsFormsApplication1
    {
        public static class Extensions
        {
            public static void SafeCall(this Control ctrl, Action callback)
            {
                if (ctrl.InvokeRequired)
                    ctrl.Invoke(callback);
                else
                    callback();
            }
        }
    }
    它只是把你要保护起来的代码作为一个回调而已。然后任何需要保护一些代码的地方都可以这样调用:using System;
    using System.Threading;
    using System.Windows.Forms;namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        private void Form1_Load(object sender, EventArgs e)
            {
                ThreadPool.QueueUserWorkItem(h =>
                {
                    for (var i = 0; i < 10000000; i++)
                    {
                        label1.SafeCall(() =>
                        {
                            label1.Text = i.ToString();
                        });
                        Thread.Sleep(100);
                    }
                });
            }    }
    }
      

  3.   

    当然,使用lamda是我的一个“坏毛病”。其实这里完全可以使用传统的匿名委托写法:using System;
    using System.Threading;
    using System.Windows.Forms;namespace WindowsFormsApplication1
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }        private void Form1_Load(object sender, EventArgs e)
            {
                ThreadPool.QueueUserWorkItem(h =>
                {
                    for (var i = 0; i < 10000000; i++)
                    {
                        label1.SafeCall(delegate()
                        {
                            label1.Text = i.ToString();
                        });
                        Thread.Sleep(100);
                    }
                });
            }    }
    }
      

  4.   

    注明一下:此文内容基于.NET 2.0
    新的.NET有很方便的实现跨线程访问的能力,参见楼上
      

  5.   

    不错,作为分享,应该使用较新的技术。
    C#的出路不在于跟java比谁更老。
      

  6.   

     
    public delegate void DoWorkD(int N);        public DoWorkD d;        public void DoWork(int Nums)
            {
                if (textBox1.InvokeRequired)
                {
                    textBox1.Invoke(d, Nums);
                }
                else
                    textBox1.Text += Nums.ToString() + "-";
            }        public void ThreadDoWork()
            {
                Thread.Sleep(new Random().Next(100, 1000));
                int i=0;
                while (true)
                {
                    d = new DoWorkD(DoWork);
                    Thread.Sleep(new Random().Next(100, 1000));
                    DoWork(i);
                    i++;
                }
            }        private void button1_Click(object sender, EventArgs e)
            {
                for (int i = 0; i < 20; i++)
                {
                    Thread a = new Thread(ThreadDoWork);
                    a.IsBackground = true;
                    a.Start();
                }
            }这样就可以了.net 2.0例子在这http://download.csdn.net/detail/wawd74520/4479927
      

  7.   

    支持一个,我也是用.net 2.0的。现在有这个InvokeHelper,应该会方便很多了。
    野比,加一个:BeginInvoke 下去会更完美一点。以前破旧的代码:   Private Delegate Sub ShowMsgCallBack(ByVal msg As String)  
       Private Delegate Sub SetBtnTextCallBack(ByVal text As String)     Private Sub ShowPanel()  
            If Me.PnlDownInfo.InvokeRequired Then  
                Dim mi As New MethodInvoker(AddressOf ShowPanel)  
                Me.BeginInvoke(mi)  
            Else  
                Me.PnlDownInfo.Visible = Not Me.PnlDownInfo.Visible  
            End If  
        End Sub   Private Sub ShowMsg(ByVal msg As String)  
            If Me.LBDownloadInfo.InvokeRequired Then  
                Dim cb As New ShowMsgCallBack(AddressOf ShowMsg)  
                '如使用Invoke会等到函数调用结束,而BeginInvoke不会等待直接往后走   
                Me.BeginInvoke(cb, New Object() {msg})  
            Else  
                Me.LBDownloadInfo.Text = msg  
                Me.LBDownloadInfo.Refresh()  
            End If  
        End Sub   Private Sub PerFinishDownLoad(ByVal fname As String)  
            If Me.LvFiles.InvokeRequired Then  
                Dim cb As New ShowMsgCallBack(AddressOf PerFinishDownLoad)  
                Me.BeginInvoke(cb, New Object() {fname})  
            Else  
                Dim item As ListViewItem  
                item = Me.LvFiles.FindItemWithText(fname)  
                If item IsNot Nothing Then  
                    item.SubItems(2).Text = "完成"  
                End If  
            End If  
        End Sub  
      
        Private Sub ResetDownLoadPrg()  
            If Me.InvokeRequired Then  
                Dim mi As New MethodInvoker(AddressOf ResetDownLoadPrg)  
                Me.BeginInvoke(mi)  
            Else  
                Me.SmoothProgressBar1.Value = 0  
                Me.LBDownloadInfo.Text = "下载信息"  
            End If  
        End Sub  
      
        Private Sub ResetDownLoadBtn()  
            If Me.BtnRunUpdate.InvokeRequired Or Me.BtnCancel.InvokeRequired Then  
                Dim mi As New MethodInvoker(AddressOf ResetDownLoadBtn)  
                Me.BeginInvoke(mi)  
            Else  
                Me.BtnRunUpdate.Enabled = True  
                Me.BtnRunUpdate.Text = "完成(&F)"  
                Me.BtnCancel.Enabled = False  
            End If  
        End Sub  
      

  8.   

    Invoke(new MethodInvoke(new Action(deleagte()
    {})));子线程中需要访问 控件的话,我现在习惯了这样,很少判断这InvokeRequired个属性了
      

  9.   

    虽然看不到,但是先Marki下。
      

  10.   

    LZ还应该反treeView,ListView等操作控件内子属性的也增加上。这样就完美了。偶的就是这样做的。
      

  11.   

    楼主用了反射吗?貌似很耗资源的说我有个思路,楼主或各位大大给点意见就是重写FORM类,写一个专门支持跨线程操作的ThreadForm,继承于Form在这个类中,
    public delegate void ThreadInvokeDelegate(string type,params object[] args);
    #region 静态方法,供其他线程调用,用于访问Form
    public static event ThreadInvokeDelegate OnThreadInvoke;
    public static ThreadInvoke(string type,params object[] args)
    {
       if(OnThreadInvoke!=null)
          OnThreadInvoke(type,args);
    }
    #endregion在真正的form中(比如Form1),构造函数里注册这个静态事件
    Form1.OnThreadInvoke+=new ThreadInvokeDelegate(Form1_OnThreadInvoke);这样就把任意线程调用Form1.ThreadInvoke方法转到了Form1_OnThreadInvoke中处理
    这里的string type作为标识,来区分Form1需要进行的不同的操作,比如刷新列表,还是写日志,还是其他什么操作以上想法本人技术有限,不能很好的实现,希望有大哥能完善,并分享一下
      

  12.   

    .Net 4.5 的async和await异步编程,貌似可以完全无视那些begin和end开头的异步方法了。。
      

  13.   

    线程间的访问默认是不允许的,但是这个开关是可以打开的,开关打开,虽然可以跨线程访问,但会带来安全问题。还有,在.net 4.0中,微软已经了为我们提供了ui线程和非UI线程之间的访问办法,可以参照control.invoke,control.beginInvoke方法
      

  14.   

    this.Control.CheckForIllegalCrossThreadCalls = false;
    夸线程访问控件,这一句代码不是就完了么。。
      

  15.   

    各位大神,我最近在使WPF主窗口中弹出一个新窗口,但老是出错,好像也涉及到多线程,但这一块实在是不怎么懂,求各位指导一下……
    http://topic.csdn.net/u/20120810/14/17b442ae-5f57-4781-80a2-75aebb5568c6.html?seed=275715377&r=79381756#r_79381756
      

  16.   

    用得着这么麻烦吗?用Timer控件不行吗?
      

  17.   

    同意,虽然谁都写得出来,但觉得写出来没任何意义,所以谁都不高兴写。
    实际是否要委托本身就看需求,多线程是为了提高效率而存在的,不是为了降低效率,到处用委托违背了多线程的存在意义。
    而实际对于简单的输出显示,应该直接对其操作,不要回调,设置CheckForIllegalCrossThreadCalls为false即可,有时候不检查能大大提高效率,而即使检测也不代表就一定能正常,因为多线程操作共享资源一般需要加锁,这和是否回调操作无关。