在WinFrom应用中,如果使用后台线程来操作界面应调用Control.Invoke()方法

在WinFrom应用中,如果需要执行一个较长的时间的调用,或要使用Web Serives从服务器取一些数据,我们通常都会使用多线程来实现这个操作,等操作完成后,再来修改一下一些控件的状态.例如下面的代码,当点击按钮,按钮和文本框都将灰化,操作完成后,再在回调函数中将按钮和文本框设为可用.
using  System;
using  System.Drawing;
using  System.Threading;
using  System.Windows.Forms;

class  App 
{

    
public static void Main() 
    
{
        Application.Run(
new MultiThreadedForm());
    }

}


class  MultiThreadedForm : Form
{

    
public MultiThreadedForm() 
    
{

        
// Create a textbox
        text.Location = new Point(1010);
        text.Size 
= new Size(5020);
        Controls.Add(text);      

        
// Create a button
        button.Text = "Beep";
        button.Size 
= new Size(5020);
        button.Location 
= new Point(8010);

        
// Register Click event handler
        button.Click += new EventHandler(OnClick); 

        Controls.Add(button);
    }
    

    
void OnClick(Object sender, EventArgs args) 
    
{
        EnableControls(
false);
        Thread myThreading 
= new Thread(new System.Threading.ThreadStart(CallBack));
        myThreading.Start();
    }



    
void CallBack()
    
{
        
// DoSomething();
        
//System.Threading.Thread.Sleep(5000);
        
//MessageBox.Show("OK");
        EnableControls(true);
    }


    
void EnableControls(Boolean enable) 
    
{
        button.Enabled 
= enable;
        text.Enabled 
= enable;
    }


    Button  button 
= new Button();
    TextBox text 
= new TextBox();
}



上面的代码通常是可以正常运行的,但是存在一个潜在的问题,回调方法并不与调用代码在相同的线程上运行,这意味着它可能会在执行应用程序另一部分的同时执行.为了避免这个问题,就需要在访问可能被程序部分使用的对象时使用同步(如lock),但这种锁定控制而进行独占访问并不是合适,反而会导致系统产生更多的问题,这时我们需要使用Control.Invoke()方法.
  Invoke()方法定义在System.Windows.Forms.Control,所有从Ssytem.Windows.Forms.Control继承的类包括From都有这个方法.众所周知,WinFrom的类库是在Win32 API的基础上实现的,而Invoke()方法在底层是用PostMessage函数来实现的,就是说调用Invoke()方法相当于向目标对象只是发送一个消息,对Control的操作还是由用户界面线程来完成,所以这个方法是线程安全的.对以上的代码,只要进行一些修改
 //声明一个委托
delegate BooleanCallBack(bool enable);
void BooleanCallBack enableControls;
//在构造函数中初始化
enableControls = new BooleanCallBack(EnableControls);
// 在CallBack中将EnableControls(true)改为
Invoke(enableControls,new object[]{true});

建一个帮助类
public   class  Updater
{
    
private TextBox textBox;
    
private Button button;
    
private bool enabled;

    
public Updater(TextBox textbox, Button button, bool enabled)
    
{
        
this.textBox = textbox;
        
this.button = button;
        
this.enabled = enabled;
    }


    
public void Update()
    
{
        
this.textBox.Enabled = enabled;
        
this.button.Enabled = enabled;
    }

}

然后在CallBack函数中将EnableContrls(true)改为
//创建一个Updater对象
Updater updater = new Updater(this.text, this.button, true);
//调用Invoke()方法
Invoke(new MethodINvoker(updater.Update));
进行了这样的处理,多线程对用户界面的操作应该是线程安全的了.

你可能感兴趣的:(ROM)