KiMoGiGi 技术文集

不在乎选择什么,而在乎坚持多久……

IT博客 首页 联系 聚合 管理
  185 Posts :: 14 Stories :: 48 Comments :: 0 Trackbacks

Scenario:

1、程式启动时,计算器在刷新时间。
2、点击“Go”,按钮无效状态,计算停止。
3、5秒后按钮恢复状态,计算重新启动。
4、2-3之间UI不能出现阻塞,即是要用多线程。



程序:
1、定义界面接口IForm

public interface IForm
    {
        
/// <summary>
        
/// 启动Button
        
/// </summary>
        void EnableButton();
        
/// <summary>
        
/// 禁用Button
        
/// </summary>
        void DisableButton();
        
/// <summary>
        
/// 停止计时器
        
/// </summary>
        void StopTimer();
        
/// <summary>
        
/// 启用计时器
        
/// </summary>
        void RecoverTimer();
    }

2、异步运行程式

public class Test
    {
        
/// <summary>
        
/// 执行
        
/// </summary>
        
/// <param name="form"></param>
        static void AsyncMethod(IForm form)
        {
            
//禁用状态
            form.DisableButton();
            form.StopTimer();

            
//停止5秒
            Thread.Sleep(5000);
        }

        
public static void Do(IForm form)
        {
            MyProcess myProcess 
= new MyProcess(AsyncMethod);

            AsyncCallback callback 
= new AsyncCallback(MyCallback);

            
//异步调用
            myProcess.BeginInvoke(form, callback, form);
        }

        
static void MyCallback(IAsyncResult ar)
        {
            AsyncResult res 
= (AsyncResult)ar;
            MyProcess del 
= (MyProcess)res.AsyncDelegate;
            del.EndInvoke(ar);

            IForm form 
= (IForm)res.AsyncState;

            
//恢复启用
            form.EnableButton();
            form.RecoverTimer();
        }
    }


3、界面代码

public partial class Form1 : Form, IForm
    {
        
public Form1()
        {
            InitializeComponent();
        }

        
private void btn_Click(object sender, EventArgs e)
        {
            Test.Do(
this);
        }

        
private void timer1_Tick(object sender, EventArgs e)
        {
            
this.lblCurrentDate.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        }

       
        
public void EnableButton()
        {
            
this.btn.Enabled = true;
        }

        
public void DisableButton()
        {
            
this.btn.Enabled = false;
        }

        
public void StopTimer()
        {
            
this.timer1.Stop();
        }

        
public void RecoverTimer()
        {
            
this.timer1.Start();
        }
}

如此调用,常理来说应该正确,但.net会抛出异常。


解决办法

根据“排错提示”,查看MSDN的“如何:对 Windows 窗体控件进行线程安全调用”即可得到答案。

如下修改界面代码即可
public void EnableButton()
        {
            
//使用控件的InvokeRequired判断执行Invoke
            if (this.btn.InvokeRequired)
            {
                
this.Invoke(new AscyUpdateControl(EnableButton));
            }
            
else
            {
                
this.btn.Enabled = true;
            }
        }

        
public void DisableButton()
        {
            
if (this.btn.InvokeRequired)
            {
                
this.Invoke(new AscyUpdateControl(DisableButton));
            }
            
else
            {
                
this.btn.Enabled = false;
            }
        }

        
public void StopTimer()
        {
            
//如没有InvokeRequired属性,简写如下代码即可
            this.Invoke(new AscyUpdateControl(delegate
            {
                
this.timer1.Stop();
            }));
        }

        
public void RecoverTimer()
        {
            
this.Invoke(new AscyUpdateControl(delegate
            {
                
this.timer1.Start();
            }));
        }

 

代码

posted on 2007-12-12 23:55 KiMoGiGi 阅读(2236) 评论(2)  编辑 收藏 引用 所属分类: C# / Winforms

评论

# re: [原]跨线程调用Winform控件 2009-03-24 10:52 wlb
这个方法已经不能再用了。  回复  更多评论
  

# re: [原]跨线程调用Winform控件 2009-03-24 13:25 KiMoGiGi
@wlb
哪里不能用了?  回复  更多评论
  

只有注册用户登录后才能发表评论。