C# 具有后台工作人员的MVP(引发异常)

C# 具有后台工作人员的MVP(引发异常),c#,winforms,multithreading,marshalling,mvp,C#,Winforms,Multithreading,Marshalling,Mvp,我的MVP解决方案有些问题,可能与线程相关。我正在运行Compact Framework 3.5并使用C#。我可以使用OpenNETCF,所以BackgroundWorker对我来说是可用的 我有一段代码(MyClient),它使用套接字连接到web服务器。代码连接到服务器并下载数据(无休止地,它是一个流),直到用户停止它。因为数据下载是无止境的,它必须在一个线程中运行,我想这就是我遇到问题的地方。 MyClient对象有一个状态,表示为enum打开,关闭,连接。 编辑-只是澄清一下,当调用My

我的MVP解决方案有些问题,可能与线程相关。我正在运行Compact Framework 3.5并使用C#。我可以使用OpenNETCF,所以BackgroundWorker对我来说是可用的

我有一段代码(
MyClient
),它使用套接字连接到web服务器。代码连接到服务器并下载数据(无休止地,它是一个流),直到用户停止它。因为数据下载是无止境的,它必须在一个线程中运行,我想这就是我遇到问题的地方。
MyClient
对象有一个状态,表示为enum
打开
关闭
连接
编辑-只是澄清一下,当调用MyClient.Start()时,它会连接到服务器。然后,它获取该连接并将其保存,以便在线程运行中使用,以不断下载数据。因此,当调用Stop()时,只需要获取一个bool标志来告诉MyClient中使用的线程停止。为清晰起见,以下为缩短版

public void Start()
{
        //...
        //Code to Connect to server...
        stream = _connection.GetStream();
        //...
        //Code to send/receive data to confirm connection...

        State = State.On;

        //Start thread to read data constantly until stopped by user setting "_continueReadingData = false"
        _continueReadingData = true;
        Thread readData = new Thread(ReadData);
        readData.IsBackground = true;
        readData.Start();
        //Note readData uses the stream variable saved above

}
视图使用
\u presenter.turn()调用presenter。演示者使用
\u model.Start()调用模型。其思想是MyClient代码启动,报告其状态更改,并在后台无休止地运行,直到用户单击“停止”。
视图
受UI组件上的Invoke/BeginInvoke调用的保护

我在下面附上了我的模型的代码示例。最初我使用了一个普通的线程,并使其正常工作,正如您在下面看到的,它被注释掉了。这里有两个问题,需要使用Invoke将到达视图的所有内容返回到UI线程,还有一个问题是引发的任何异常都不会返回到UI线程,因此无法处理,并且会使应用程序崩溃。这是我试图解决的两个问题

此后,我尝试了BackgroundWorker(在OpenNETCF中可用,就像.NET2.0以后的普通BackgroundWorker一样),以处理异常和封送,如下代码所示。但有了这个,我无法让它工作。相反,当状态更改并报告回GUI时。尽管调用了Invoke,但它会抱怨
invalidooperationexception-“在创建窗口句柄之前,不能对控件调用Invoke或BeginInvoke”
。做一些研究,听起来线程似乎正在创建自己的控件集。在这一点上,我感到困惑

有谁能帮我演示一下如何正确地启动/结束模型中的线程,使它们在后台运行,将异常返回到要处理的模型,并将执行重新分配到UI线程,这样就不必在每个控件上使用Invoke。我相信这一定是可能的

public class Model
{
    public event EventHandler DataChanged;
    public event EventHandler ErrorRaised;
    private MyClient _client = new MyClient();

    public Model()
    {
        //Register to events
        _client.StateChanged += ClientStateChanged;

        //Setup current values
        State = _client.State;
    }

    void ClientStateChanged(NTRIPClient client, NTRIPState newState)
    {
        State = newState;
    }

    private State _state;
    public State State
    {
        get { return _state; }
        set
        {
            if (_state != value)
            {
                _state = value;
                if (DataChanged != null)
                {
                    DataChanged(this, EventArgs.Empty);
                }
            }
        }
    }

    public void Start()
    {
        //Thread thread = new Thread(_NTRIPClient.Start);
        //thread.IsBackground = true;
        //thread.Start();

        BackgroundWorker bgWorker = new BackgroundWorker();
        bgWorker.DoWork += _client.Start();
        bgWorker.RunWorkerCompleted += bgWorker_RunWorkerCompleted;
    }

    void bgWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        if(e.Error != null)
        {
            if (ErrorRaised != null)
            {
                ErrorRaised(this, new ErrorEventArgs(e.Error));
            }
        }
    }
}

问题是,演示者是在视图中创建的,而视图又创建了模型。该模型是在视图完全构建之前调用的,因此尚未创建控件


由于一个简单的错误而产生的一个大问题:)

上也有类似的讨论。也许那会有帮助,谢谢拉尔夫。我在发帖前读过这篇文章。我想差不多了。但是ProgressUpdated/Completed对我没有帮助,因为MyClient代码不知道它正在后台工作程序中运行,所以不会引发ProgressUpdated事件。此外,还需要通知GUI属性的更改,即状态。然而,当状态更改时,该事件会在非UI线程上引发。我想知道我的客户是否会被改写,以某种方式支持后台工作人员