1

我一直在搜索 stackoverflow 以寻找将数据从线程编组回 UI 线程的方法,并在 3.5 中找到了各种方法。

对我来说更优雅的解决方案之一;虽然我仍在学习 lambdas 和闭包,但这个解决方案Control.Invoke with input Parameters

我不完全理解代码,但我知道如何使用它,它并不能完全解决我的问题。

我想调用调用并将字符串传递给另一个方法(DisplayStatusUpdate(msg))。任何指针将不胜感激。

    private void FireEventAppender_OnMessageLogged(object sender, MessageLoggedEventArgs e)
    {
        DisplayStatusUpdate(e.LoggingEvent.RenderedMessage);
    }

    private void DisplayStatusUpdate(string text)
    {
         _StatusTextBox.Text = _StatusTextBox.Text + text;
         _StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
         _StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
         _StatusTextBox.ScrollToCaret();
    }
4

2 回答 2

5

您可以使用任意数量的参数来执行此操作,例如:

private void FireEventAppender_OnMessageLogged(object sender, MessageLoggedEventArgs e)
{
    DisplayStatusUpdate(e.LoggingEvent.RenderedMessage);
}

private delegate void DisplayStatusUpdateDelegate(string text);

private void DisplayStatusUpdate(string text)
{
     if(InvokeRequired)
         this.Invoke(new DisplayStatusUpdateDelegate(DisplayStatusUpdate), text);
     else
     {
         _StatusTextBox.Text = _StatusTextBox.Text + text;
         _StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
         _StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
         _StatusTextBox.ScrollToCaret();
     }
}

我在当前项目中使用的另一种方法可以显着减少代码。详情在这里

如果您实现此方法,您将需要:

使用 AOP 工厂创建表单:

Form f = AOPFactory.Create<Form1>();
Application.Run(f);

然后你只需用 [RunInUIThread] 属性装饰事件处理程序。它使用 Castle 的方法拦截模型在需要时自动调用。

于是,上面的代码就变成了:

private void FireEventAppender_OnMessageLogged(object sender, MessageLoggedEventArgs e)
{
    _StatusTextBox.Text = _StatusTextBox.Text + text;
    _StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
    _StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
    _StatusTextBox.ScrollToCaret();
}

性能方面,它似乎是可比的,稍微慢一些,但取决于你在做什么,它可能没问题,它肯定需要更少的代码。

于 2009-08-23T21:44:56.333 回答
2

如果您使用的是 C# 3.5(或更高版本),则可以使用捕获的变量,这可以简化代码:

private void DisplayStatusUpdate(string text)
{
    this.Invoke(new MethodInvoker(() => 
    {
         _StatusTextBox.Text = _StatusTextBox.Text + text;
         _StatusTextBox.Text = String.Format("{0}\r\n", _StatusTextBox.Text);
         _StatusTextBox.SelectionStart = _StatusTextBox.Text.Length - 1;
         _StatusTextBox.ScrollToCaret();
    }));
}

编译器在幕后所做的是生成一个类来保存文本,创建一个MethodInvoker委托,并将该委托和生成的类的实例传递给Invoke方法。在上面的设计中,即使代码已经在同一个线程上运行,这当然也会做不必要的创建委托和调用 Invoke 的工作;但我认为不应该经常调用这样的方法,因为这将是一个性能问题。

如果您愿意,可以将 MethodInvoker 的使用替换为无参数Action委托或任何其他返回的无参数委托void

于 2009-08-23T21:54:41.133 回答