C#在其他线程中修改UI 举例

本想翻译来着,后来想想算了,一是比较懒,二是没时间,三是觉得没必要。有需要的话评论原文地址:http://kristofverbiest.blogspot.sg/2007/02/simple-pattern-to-invoke-gui-from.html


If you are making a GUI application and you are using multiple threads, there is one very important rule: GUI controls can only be accessed from the GUI thread. This is inherent to Windows development and is not a limitation of .NET.

Let me first say that although this seems to be an annoyance for the developer, this is actually a great thing! It means that while you are developing a GUI application you generally don't have to worry about threading issues (locks, deadlocks) because you know that all GUI-access is done from a single thread.

But of course there are situations where you want to start background processing on a seperate thread and access the GUI from this thread. Take for instance this simple example:

  
  
public void SetTitleUnsafe( string title) { // When invoked from another thread, this next statement is illegal: this .Text = title; }

If you call this method from a thread that is not a GUI thread, everything may seem to go well at first sight. But because we violated the very important rule, the behaviour of our application is now undefined. Things may (and will) start to go wrong very unpredictably, sometimes much later when there is no obvious relationship with the violation that was made. This makes this problem very hard to find. Among the things that could happen is GUI-events to become 'lost' and the GUI to become unresponsive.

Luckily, form Visual Studio 2005 onward you get a nice error-message when you violate this rule while the debugger is attached:

So now you at least get an immedeate notification that you made a mistake. This one of the reasons why I advise to run your code from Visual Studio (using F5) while you are developing.

To get around our threading-violation, Winforms provides these helper-methods: BeginInvoke, EndInvoke, Invoke, InvokeRequired. But even with these methods available it may not be obvious how to use them in a correct and simple way.

That's why I present this pattern:

  
  
delegate void Invoker( string parameter); public void SetTitleSafe( string title) { if ( this .InvokeRequired) { // Execute the same method, but this time on the GUI thread this .BeginInvoke( new Invoker(SetTitleSafe), title); // we return immedeately return ; } // From here on it is safe to access methods and properties on the GUI // For example: this .Text = title; }

As you can see, you will need to define a delegate that matches your method (or use an existing delegate that is defined elsewhere, such as the System.Windows.Forms.MethodInvoker). This is how the pattern works:

  • When the method is called from a thread that is not the GUI thread, InvokeRequired will be true. The method will be wrapped in a delegate and passed to the BeginInvoke method (together with the parameters). We return immedeately. BeginInvoke guarantees that some time later our method will be called on the GUI thread.
  • When the method is called on the GUI thread, InvokeRequired returns false so we just go forward and access the GUI in any way we like.

This is in my opinion the simplest and shortest pattern that is always correct.

From .NET 2.0 onwards the same pattern can be written using an anonymous method but that is less readable in my opinion, so I prefer to keep this pattern.

Also in .NET 2.0 you can use the BackgroundWorker class that handles all the details behind your back. But the same principle still applies: never access GUI from another thread!

第一条评论的方法也可以:

I prefer a small helper class like this one, it makes the code even cleaner and shorter:

using System.Windows.Forms;

public static class ControlsHelper
{
    public static void SyncBeginInvoke(control, MethodInvoker del)
    {
        if ((control != null) && control.InvokeRequired)
            control.BeginInvoke(del, null);
        else
            del();
    }
}

private void SetLabelText(int number)
{
    ControlsHelper.SyncBeginInvoke(this, delegate()
        {  
            label.Text = number.ToString();
        });
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值