C# 采用系统委托方式处理线程内操作窗体控件

一、System.Windows.Forms.MethodInvoker 类型是一个系统定义的委托,用于调用不带参数的方法。
  
  
  
  
private Thread myThread;

private void Form1_Load( object sender, EventArgs e)
{
myThread
= new Thread( new ThreadStart(RunsOnWorkerThread));
myThread.Start();
}

private void RunsOnWorkerThread()
{
MethodInvoker mi
= new MethodInvoker(SetControlsProp);
BeginInvoke(mi);
}

private void SetControlsProp()
{
label1.Text
= " myThread线程调用UI控件 " ;
}


二、直接用System.EventHandle(可带参数)
 
  
  
  
  
private Thread myThread;

private void Form1_Load( object sender, EventArgs e)
{
myThread
= new Thread( new ThreadStart(RunsOnWorkerThread));
myThread.Start();
}

private void RunsOnWorkerThread()
{
// DoSomethingSlow();
string pList = " myThread线程调用UI控件 " ;
label1.BeginInvoke(
new System.EventHandler(UpdateUI), pList);
}

// 直接用System.EventHandler,没有必要自定义委托
private void UpdateUI( object o, System.EventArgs e)
{
// UI线程设置label1属性
label1.Text = o.ToString() + " 成功! " ;
}
包装Control.Invoke
虽然第二个方法中的代码解决了这个问题。但它非常烦琐,如果辅助线程希望在结束的时候提供更多的反馈信息,而不是简单地给出
"Finieshed!"消息,则BeginInvoke过于复杂的使用方法会令人剩畏。为了传达其他消息,例如“正在处理”、“一切顺利”等等,
需要设法向UpdateUI函数传递一个参数。可能还需要添加一个进度栏以提高反馈能力。这么多次调用BeginInvoke可能导致辅助线程
受该代码支配,这样不仅会造成不便,而且考虑到辅助线程与UI的协调性,这样设计也不好。对这些分析之后,我们认为包装函数可
以解决这两个问题
 private Thread myThread;
        private void Form1_Load(object sender, EventArgs e)
        {
            myThread = new Thread(new ThreadStart(RunOnWorkerThread));
            myThread.Start();
        }
 
        private void RunOnWorkerThread()
        {
            for (int i = 0; i < 100; i++)
            {
                showProgress(Convert.ToString(i), i);
                Thread.Sleep(100);
            }
        }
 

        public void showProgress(string msg, int percentDone)
        {
            System.EventArgs e = new MyProgressEvents(msg, percentDone);
            object[] pList = { this, e };
            BeginInvoke(new MyProgressEventsHandler(UpdateUI), pList);
        }
 
        private delegate void MyProgressEventsHandler(object sender, MyProgressEvents e);
        private void UpdateUI(object sender, MyProgressEvents e)
        {
            lblStatus.Text = e.Msg;
            myProgressControl.Value = e.PercentDone;
        }
 
        public class MyProgressEvents : EventArgs
        {
            public string Msg;
            public int PercentDone;
 
            public MyProgressEvents(string msg, int per)
            {
                Msg = msg;
                PercentDone = per;
            }
        }
ShowProgress方法对将调用引向正确线程的工作进行封装。这意味着辅助线程代码不用担心需要过多的关注UI细节,而只要定期调用
ShowProgress即可
如果我提供一个设计为可从任何线程调用的公共方法,则完全有可能某人会从UI线程调用这个方法。在这种情况下,没必要调用
BeginInvoke,因为我已经处于正确的线程中。调用Invoke完全是浪费时间和资源,不如直接调用适当的方法。为了避免这个情况,
Control类将公开一个称为InvokeRequired的属性,这是“只限UI线程”规则的另一个例外。它可从任何线程读取,如果调用线程是
UI线程,则返回假,其他线程则返回真。这以为着:我可以按以下方式修改包装
 public void ShowProgress(string msg, int percentDone)
        {
            if (InvokeRequired)
            {

                //as before
                //..
            }
            else
            {
                //we're already on the UI thread just
                //call straight through
                UpdateUI(this, new MyProgressEventsHandler(msg, percentDone));
            }
        }





三、演示程序
              线程中调用部分:
结束。
    
    
    
    
// 初始化参数列表
List < String > paramList = new List < string > ();
paramList.Add(
" 0 " );
paramList.Add(
"" );

// 这里采用系统委托的方式,实现线程内操作系统界面控件。
paramList[ 0 ] = " 0 " ; paramList[ 1 ] = " 清除屏幕信息 " ;
lstBoxCatchData.BeginInvoke(
new System.EventHandler(UpdateListBox),
paramList);
    
    
    
    
/// <summary>
/// 提供给系统委托事件调用,解决线程内操作界面控件的目的
/// </summary>
/// <param name="obj"></param>
/// <param name="e"></param>
private void UpdateListBox( object obj,System.EventArgs e)
{
// 强制类型转换
List < String > paramList = (List < string > )obj;
if (paramList[ 0 ] == " 0 " )
{
this .lstBoxCatchData.Items.Clear();
}
else if (paramList[ 0 ] == " 1 " )
{
this .lstBoxCatchData.Items.Add(paramList[ 1 ].ToString());
}
}

你可能感兴趣的:(线程,C#,休闲,系统委托,操作窗体控件)