自动化 InvokeRequired 代码模式 [英] Automating the InvokeRequired code pattern

查看:26
本文介绍了自动化 InvokeRequired 代码模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我痛苦地意识到人们需要在事件驱动的 GUI 代码中编写以下代码模式的频率,其中

I have become painfully aware of just how often one needs to write the following code pattern in event-driven GUI code, where

private void DoGUISwitch() {
    // cruisin for a bruisin' through exception city
    object1.Visible = true;
    object2.Visible = false;
}

变成:

private void DoGUISwitch() {
    if (object1.InvokeRequired) {
        object1.Invoke(new MethodInvoker(() => { DoGUISwitch(); }));
    } else {
        object1.Visible = true;
        object2.Visible = false;
    }
}

这在 C# 中是一种笨拙的模式,既要记住又要键入.有没有人想出某种捷径或构造来在一定程度上自动化?如果有一种方法可以将函数附加到执行此检查的对象而无需执行所有这些额外工作,例如 object1.InvokeIfNecessary.visible = true 类型快捷方式,那就太酷了.

This is an awkward pattern in C#, both to remember, and to type. Has anyone come up with some sort of shortcut or construct that automates this to a degree? It'd be cool if there was a way to attach a function to objects that does this check without having to go through all this extra work, like a object1.InvokeIfNecessary.visible = true type shortcut.

之前的答案讨论了仅调用的不切实际Invoke() 每次,即使这样 Invoke() 语法既低效又仍然难以处理.

Previous answers have discussed the impracticality of just calling Invoke() every time, and even then the Invoke() syntax is both inefficient and still awkward to deal with.

那么,有没有人想出任何捷径?

So, has anyone figured out any shortcuts?

推荐答案

Lee 的方法可以进一步简化

Lee's approach can be simplified further

public static void InvokeIfRequired(this Control control, MethodInvoker action)
{
    // See Update 2 for edits Mike de Klerk suggests to insert here.

    if (control.InvokeRequired) {
        control.Invoke(action);
    } else {
        action();
    }
}

而且可以这样称呼

richEditControl1.InvokeIfRequired(() =>
{
    // Do anything you want with the control here
    richEditControl1.RtfText = value;
    RtfHelpers.AddMissingStyles(richEditControl1);
});

无需将控件作为参数传递给委托.C# 会自动创建一个闭包.

There is no need to pass the control as parameter to the delegate. C# automatically creates a closure.

如果你必须返回一个值,你可以使用这个实现:

If you must return a value, you can use this implementation:

private static T InvokeIfRequiredReturn<T>(this Control control, Func<T> function)
{
    if (control.InvokeRequired) {
        return (T)control.Invoke(function);
    } else {
        return function();
    }
}


更新:

根据其他几个海报Control可以概括为ISynchronizeInvoke:

According to several other posters Control can be generalized as ISynchronizeInvoke:

public static void InvokeIfRequired(this ISynchronizeInvoke obj,
                                         MethodInvoker action)
{
    if (obj.InvokeRequired) {
        var args = new object[0];
        obj.Invoke(action, args);
    } else {
        action();
    }
}

DonBoitnott 指出,与 Control 不同,ISynchronizeInvoke 接口需要 Invoke 方法的对象数组作为 action 的参数列表.

DonBoitnott pointed out that unlike Control the ISynchronizeInvoke interface requires an object array for the Invoke method as parameter list for the action.

更新 2

Mike de Klerk 建议的编辑(请参阅第一个代码片段中的注释以了解插入点):

Edits suggested by Mike de Klerk (see comment in 1st code snippet for insert point):

// When the form, thus the control, isn't visible yet, InvokeRequired  returns false,
// resulting still in a cross-thread exception.
while (!control.Visible)
{
    System.Threading.Thread.Sleep(50);
}

参见 ToolmakerSteve 的nawfal 的评论如下,表示对此建议的担忧.

See ToolmakerSteve's and nawfal's comments below for concerns about this suggestion.

这篇关于自动化 InvokeRequired 代码模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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