0

我们目前有一个从串行通信中读取数据的应用程序。在整个应用程序中,我们需要在 UI 中显示这些数据,因此我们创建了一个使用 BeginInvoke 更新文本框/标签/数字/进度条的方法。

然而,这开始变得很麻烦,因为每个控件都需要自己的“Setter”,所以我们已经有 20 多个方法,它们基本上都做同样的事情。

虽然我可以看到一种将其泛化为特定控件的简单方法(例如,只有 1 个用于标签,1 个用于文本框),但最好只有 1 个(可能是扩展)方法,我们可以调用它来更新 UI 中的数据.

这是我们原来的方法到处张开:

private void SetCell1Cell2Async(decimal value)
    {
        if (spinCell1Cell2.InvokeRequired)
        {
            spinCell1Cell2.BeginInvoke(new EventHandler(delegate
            {
                spinCell1Cell2.Value = value;
            }));
        }
        else
        {
            if (spinCell1Cell2.IsDisposed) return; // Do not process if the control has been disposed of
            if (spinCell1Cell2.IsHandleCreated)
            {
                // This handle may not be created when creating this form AFTER data is already flowing
                // We could capture this data for future display (i.e. via deferUpdate = true or similar), but it is easier to ignore it
                // i.e. Do Nothing
                return;
            }
            spinCell1Cell2.Value = value;
        }
    }

这是我们当前的方法(这适用于使用该Text属性显示数据的控件):

delegate void SetTextAsyncCallback(Control ctrl, string text);
public static void SetTextAsync(this Control invoker, string text)
{
    if (invoker.InvokeRequired)
    {
        invoker.BeginInvoke(new SetTextAsyncCallback(SetTextAsync), invoker, text);
    }
    else
    {
        if (invoker.IsDisposed) return; // Do not process if the control has been disposed of
        if (!invoker.IsHandleCreated)
        {
            // This handle may not be created when creating this form AFTER data is already flowing
            // We could capture this data for future display (i.e. via deferUpdate = true or similar), but it is easier to ignore it
            // i.e. Do Nothing
            return;
        } 
        invoker.Text = text;
    }
}

如您所见,此方法适用于任何使用该Text属性来显示其数据的东西。

理想情况下,我希望能够“传入”要更新的属性,并提供一种需要string, double,decimal等的方法boolean,但是我有点迷失从这里去哪里。

任何帮助表示赞赏。

4

1 回答 1

2

我会制定一个更通用的解决方案,在表单中使用类似这样的内容:

delegate void ActionCallback();

private void SetText()
{
    this.SafeInvoke(() =>
        {
            if (spinCell1Cell2.IsDisposed) return;
            if (!spinCell1Cell2.IsHandleCreated) return;
            // Do stuff
        });
}

private void SafeInvoke(ActionCallback action)
{
    if (this.InvokeRequired)
        this.Invoke(action);
    else
        action();
}

使用委托,您只需声明一次实际操作,而执行的类型稍后决定(在 SafeInvoke 方法中)。如果您希望有一些扩展方法,这里有一个示例:

public delegate void ActionCallback();

public static void SafeInvoke(this Form form, ActionCallback action)
{
    if (form.InvokeRequired)
        form.Invoke(action);
    else
        action();
}

public static void SafeSetText(this Control ctl)
{
    var form = ctl.FindForm();
    if (form == null) return; // or do something else

    form.SafeInvoke(() =>
        {
            // Do stuff
        });
}

编辑 再次阅读您的问题后,我注意到这并不是您真正要问的,所以我会给你一个更相关的例子:

public static void SafeUpdate<T>(this T ctl, ActionCallback action) where T : Control
{
    var form = ctl.FindForm();
    if (form == null) return; // or do something else

    SafeInvoke(action);
}

// Then in some other method
{
    textBox1.SafeUpdate(() =>
    {
        textBox1.Text = "123";
        textBox1.ForeColor = Color.Red;
    });
}
于 2012-10-03T09:35:04.103 回答