【问题标题】:MVP with Background Worker (Exception raised)带后台工作人员的 MVP(引发异常)
【发布时间】:2012-02-13 18:25:11
【问题描述】:

我的 MVP 解决方案遇到了一些问题,可能与线程有关。我正在运行 Compact Framework 3.5 并使用 C#。我可以使用 OpenNETCF,所以我可以使用 BackgroundWorker。

我有一段代码 (MyClient) 使用套接字连接到 Web 服务器。代码连接到服务器并下载数据(无休止地,它是一个流),直到用户停止它。因为数据的下载是无止境的,所以它必须在一个线程中运行,我认为这就是我遇到问题的地方。 MyClient 对象有一个状态,表示为枚举 OnOffConnecting编辑 - 澄清一下,当调用 MyClient.Start() 时,它会连接到服务器。然后它会获取该连接并将其保存以在 Thread 运行中使用以不断下载数据。因此,当调用 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

}

使用_presenter.TurnOn(); 查看通话演示者。演示者使用_model.Start(); 调用模型。这个想法是启动 MyClient 代码,报告其状态更改并在后台无休止地运行,直到用户单击停止。 View 受到对 UI 组件的 Invoke/BeginInvoke 调用的保护。

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

我已经尝试过 BackgroundWorker(在 OpenNETCF 中可用,就像 .Net 2.0 及更高版本中的普通 BackgroundWorker)来处理异常和编组,如下面的代码所示。但是有了这个,我无法让它工作。相反,当状态更改并报告回 GUI 时。尽管调用了 Invoke,但它会向 InvalidOperationException - "Invoke or BeginInvoke cannot be called on a control until the window handle has been created" 抱怨。做一些研究,听起来几乎就像线程正在创建自己的一组控件。在这一点上我很困惑。

谁能帮我看看如何正确启动/结束模型中的线程,以便它们在后台运行,将异常引发回要处理的模型,并将执行编组回 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));
            }
        }
    }
}

【问题讨论】:

  • stackoverflow.com/questions/1862590/… 也有类似的讨论。也许这会有所帮助
  • 谢谢拉尔夫。我在发帖前读过那个。我认为它很接近。但是 ProgressUpdated/Completed 对我没有帮助,因为 MyClient 代码不知道它正在后台工作人员中运行,因此不会引发进度更新事件。还需要通知 GUI 属性更改,即状态。然而,当状态改变时,该事件会在非 UI 线程上引发。我想知道是否要重写我的客户以某种方式支持后台工作人员

标签: c# winforms multithreading marshalling mvp


【解决方案1】:

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

一个简单的错误引起的大问题:)

【讨论】:

    猜你喜欢
    • 2016-06-18
    • 1970-01-01
    • 1970-01-01
    • 2012-06-30
    • 1970-01-01
    • 2023-03-16
    • 1970-01-01
    • 2012-06-11
    • 2014-04-14
    相关资源
    最近更新 更多