MVP с Background Worker (Исключение поднято)

У меня возникли проблемы с моим решением MVP, возможно, связанным с потоками. Я использую Compact Framework 3.5 и использую C#. Я могу использовать OpenNETCF, поэтому мне доступен BackgroundWorker.

У меня есть кусок кода (MyClient), который подключается к веб-серверу с помощью сокетов. Код подключается к серверу и загружает данные (бесконечно, их поток), пока пользователь не остановит их. Поскольку загрузка данных бесконечна, ее нужно запускать в потоке, и я думаю, что здесь возникают проблемы. MyClient объект имеет состояние, представленное как enum On, Off, Connecting,Редактировать - просто чтобы уточнить, когда MyClient.Start() вызывается, он подключается к серверу. Затем он берет это соединение и сохраняет его для использования в потоке потоков для постоянной загрузки данных. Поэтому, когда вызывается Stop(), ему просто нужно получить флаг bool, чтобы сообщить потоку, используемому внутри MyClient, о Stop. Укороченный вариант ниже для наглядности.

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 защищен вызовами Invoke/BeginInvoke для компонентов пользовательского интерфейса.

Я приложил пример кода моей модели ниже. Первоначально я использовал нормальный поток и получил его работать, как вы можете видеть ниже, он закомментирован. Здесь есть две проблемы: необходимость использовать Invoke для маршалинга обратно в поток пользовательского интерфейса для всего, что достигает представления, а также проблема в том, что любые возникающие исключения не возвращаются в поток пользовательского интерфейса, поэтому вместо этого они не могут быть обработаны и приводят к аварийному завершению. приложение. Это две проблемы, которые я пытаюсь решить.

С тех пор я попробовал BackgroundWorker (доступный в OpenNETCF, точно так же как обычный BackgroundWorker в.Net 2.0 и более поздних версиях), чтобы обрабатывать исключения и сортировку, как в коде ниже. Но с этим я не могу заставить его работать. Вместо этого, когда состояние изменяется и возвращается в GUI. Хотя Invoke называется, он жалуется InvalidOperationException - "Invoke or BeginInvoke cannot be called on a control until the window handle has been created", В некоторых исследованиях кажется, что поток создает собственный набор элементов управления. На данный момент я в замешательстве.

Может кто-нибудь протянуть руку, чтобы показать мне, как правильно запускать / завершать потоки в модели, чтобы они выполнялись в фоновом режиме, вызывать исключения обратно в обрабатываемую модель и маршалировать выполнение обратно в поток пользовательского интерфейса, чтобы у вас не было использовать 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));
            }
        }
    }
}

1 ответ

Решение

Проблема оказалась в том, что презентатор создавался в представлении, которое, в свою очередь, создавало модель. Эта модель была вызвана до того, как представление было полностью построено, и, таким образом, элементы управления еще не были созданы.

Большой вопрос из-за простой ошибки:)

Другие вопросы по тегам