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

时间:2015-01-23 14:35:42

标签: c# multithreading winforms invoke

Windows表单应用程序,在单独的线程中进行繁重的处理。在处理的某个地方,我需要从用户那里获得一些反馈(比如询问有关视觉输出到另一个设备的一些问题)。如果我要在UI层中执行此操作,我会非常乐意使用控件Invoke并执行此操作。处理在业务层完成。我问过业务层中的每个人,没有人知道像ControlInvokeMainForm等关键字。我如何通知主表单并获取输入? (事件?还是我错过了一些简单的事情?)

2 个答案:

答案 0 :(得分:2)

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

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

我个人的偏好是让图层直接相互通信,所以在这种情况下,我会让业务层与请求输入的表示层进行通信,然后表示层会将请求编组到通过Invoke查看(UI)本身。

答案 1 :(得分:2)

一种方法是在您的业务层中创建一个event,您可以从控件/表单代码连接到该业务层。当您的控件/表单收到事件时,将封送回调用Invoke / BeginInvoke的UI线程,以便相应地更新您的控件。

例如,您的型号代码:

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

当您致电(或广播)该活动时,通常会通过“开启”方式(make the call thread-safe执行此操作 - 另请参阅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代码可以与抽象内容对话,这意味着您可以在需要时更改基础类型(例如,用于测试)。