从分层应用程序中的后台线程调用

Invoke from background thread in layered application

Windows 形成应用程序,在单独的线程中进行繁重的处理。在处理的某个地方,我需要从用户那里得到一些反馈(比如询问一些关于视觉输出到另一台设备的问题)。如果我要在 UI 层中执行此操作,我会非常乐意使用控件的 Invoke 来执行此操作。处理在业务层完成。问了下业务层的大家,没有人知道ControlInvokeMainForm等关键字,怎么通知Main form获取输入呢? (事件?还是我漏掉了一些简单的东西?)

您需要让您的请求从业务层向上传播,然后从您的 UI 中的表示层调用它。

正如您在评论中所建议的那样,一种方法是使用从业务层触发并由表示层处理的事件,但这取决于您是否要构建您的应用程序使用事件在层之间进行通信。

我个人的偏好是让各层直接相互通信,因此在这种情况下,我会让业务层与请求输入的表示层通信,然后由表示层整理请求通过 Invoke.

到视图 (UI) 本身

一种方法是在您的业务层中创建一个 event,您从中连接到您的 control/form 代码。当您的 control/form 收到事件时,编组回 UI 线程调用 Invoke/BeginInvoke 以相应地更新您的控件。

例如,在您的型号代码中:

public class ModelFoo
{
    public event EventHandler SomethingInterestingHappened;
...

当您调用(或广播)事件时,通常的做法是通过 "On" 方法 (make the call thread-safe - see also this):

    private void
    OnSomethingInterestingHappened
        ()
    {
        var SomethingInterestingHappenedCopy = SomethingInterestingHappened;
        if (SomethingInterestingHappenedCopy != null)
        {
            // TODO add your event data in the second args here
            SomethingInterestingHappenedCopy (this, EventArgs.Empty);
        }
    }

然后从您的 UI 主题订阅它,例如:

ModelFoo.SomethingInterestingHappened += SomethingInterestingHappenedHandler;

其中:

    private void SomethingInterestingHappenedHandler(object sender, EventArgs e)
    {
// You can call if(this.InvokeRequired) here, since 
// you might already be on the UI thread. 
// However from other threads call Invoke/BeginInvoke if wanting 
// to process synchronously/asynchronously depending on what you need and
// you need to update a control object.
            Invoke(new MethodInvoker(delegate
            {...

我发现事件非常有用,因为它 feels like 您可以很好地将 UI 与模型分离。事件也可以在接口上定义,因此 UI 代码可以与抽象的东西对话,这意味着您可以在需要时更改基础类型(例如用于测试)。