难道适当延长控制,以提供一致的安全调用/ BeginInvoke的功能? [英] Is it appropriate to extend Control to provide consistently safe Invoke/BeginInvoke functionality?

查看:125
本文介绍了难道适当延长控制,以提供一致的安全调用/ BeginInvoke的功能?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我维护的旧应用程序,严重违反了的WinForms跨线程更新规则的过程中,我创建了下面的扩展方法,以此来迅速解决非法调用时,我发现他们:

In the course of my maintenance for an older application that badly violated the cross-thread update rules in winforms, I created the following extension method as a way to quickly fix illegal calls when I've discovered them:

/// <summary>
/// Execute a method on the control's owning thread.
/// </summary>
/// <param name="uiElement">The control that is being updated.</param>
/// <param name="updater">The method that updates uiElement.</param>
/// <param name="forceSynchronous">True to force synchronous execution of 
/// updater.  False to allow asynchronous execution if the call is marshalled
/// from a non-GUI thread.  If the method is called on the GUI thread,
/// execution is always synchronous.</param>
public static void SafeInvoke(this Control uiElement, Action updater, bool forceSynchronous)
{
    if (uiElement == null)
    {
        throw new ArgumentNullException("uiElement");
    }

    if (uiElement.InvokeRequired)
    {
        if (forceSynchronous)
        {
            uiElement.Invoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
        }
        else
        {
            uiElement.BeginInvoke((Action)delegate { SafeInvoke(uiElement, updater, forceSynchronous); });
        }
    }
    else
    {
        if (!uiElement.IsHandleCreated)
        {
            // Do nothing if the handle isn't created already.  The user's responsible
            // for ensuring that the handle they give us exists.
            return;
        }

        if (uiElement.IsDisposed)
        {
            throw new ObjectDisposedException("Control is already disposed.");
        }

        updater();
    }
}

使用范例:

this.lblTimeDisplay.SafeInvoke(() => this.lblTimeDisplay.Text = this.task.Duration.ToString(), false);

我喜欢我如何利用封闭阅读,也尽管forceSynchronous需要是真实的在这种情况下:

I like how I can leverage closures to read, also, though forceSynchronous needs to be true in that case:

string taskName = string.Empty;
this.txtTaskName.SafeInvoke(() => taskName = this.txtTaskName.Text, true);

我不怀疑这个方法的固定了在传统code非法呼叫的用处,但对于新的code?

I don't question the usefulness of this method for fixing up illegal calls in legacy code, but what about new code?

这是好设计使用这种方法在一块新的软件更新UI时,你可能不知道什么线程试图更新UI,还是应该新的WinForms code一般含有特定的,专门的法相应的的invoke()产权相关的所有这样的UI更新的管道? (我会首先尝试使用其他适当的背景处理技术,当然,例如BackgroundWorker的。)

Is it good design to use this method to update UI in a piece of new software when you may not know what thread is attempting to update the ui, or should new Winforms code generally contain a specific, dedicated method with the appropriate Invoke()-related plumbing for all such UI updates? (I'll try to use the other appropriate background processing techniques first, of course, e.g. BackgroundWorker.)

有趣的是这不会对<一个工作href=\"http://msdn.microsoft.com/en-us/library/system.windows.forms.toolstripitem.aspx\">ToolStripItems.我只是最近发现,他们直接从组件而不是从的控制。相反,含的ToolStrip 的调用应该被使用。

Interestingly this won't work for ToolStripItems. I just recently discovered that they derive directly from Component instead of from Control. Instead, the containing ToolStrip's invoke should be used.

一些意见建议:

if (uiElement.InvokeRequired)

应该是:

if (uiElement.InvokeRequired && uiElement.IsHandleCreated)

考虑以下 MSDN文档

这意味着,InvokeRequired可以
  返回false 如果不需要调用
  (发生在同一个线程调用)
  或如果对照上创建
  不同的线程但控制的
  手柄尚未建立。

This means that InvokeRequired can return false if Invoke is not required (the call occurs on the same thread), or if the control was created on a different thread but the control's handle has not yet been created.

在的情况下控件的句柄
  尚未创建,您应该
  不是简单地调用属性,方法,
  或控制的事件。这可能
  导致控件的句柄是
  在后台线程创建的,
  隔离的线程控制
  未经消息泵和使
  应用程序不稳定​​。

In the case where the control's handle has not yet been created, you should not simply call properties, methods, or events on the control. This might cause the control's handle to be created on the background thread, isolating the control on a thread without a message pump and making the application unstable.

您可以防止这种情况下,由
  还检查的价值
  InvokeRequired当IsHandleCreated
  返回在后台线程错误的。

如果控制是在不同的线程创建,但在控件的句柄尚未创建 InvokeRequired 返回false。这意味着,如果 InvokeRequired 收益真正 IsHandleCreated 总会是真实的。再次测试它是多余的和不正确的。

If the control was created on a different thread but the control's handle has not yet been created, InvokeRequired returns false. This means that if InvokeRequired returns true, IsHandleCreated will always be true. Testing it again is redundant and incorrect.

推荐答案

我喜欢的总体思路,但我确实看到一个问题。它处理EndInvokes是很重要的,也可以有资源泄漏。我知道很多人不相信这一点,但它确实是真的。

I like the general idea, but I do see one problem. It is important to process EndInvokes, or you can have resource leaks. I know a lot of people don't believe this, but it really is true.

这里有一个链接谈论它。还有其他人。

Here's one link talking about it. There are others as well.

但我的主要反应是:是的,我想你已经有了一个不错的主意此处

But the main response I have is: Yes, I think you've got a nice idea here.

这篇关于难道适当延长控制,以提供一致的安全调用/ BeginInvoke的功能?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆