2012-02-13 2 views
0

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

У меня есть фрагмент кода (MyClient), который подключается к веб-серверу с использованием сокетов. Код подключается к серверу и загружает данные (бесконечно, его поток), пока пользователь не остановит его. Поскольку загрузка данных бесконечна, ее нужно запускать в потоке, и я думаю, что это то, где я получаю проблемы. Объект MyClient имеет состояние, представленное как перечисление On, , Connecting. Редактировать - Просто для пояснения, когда 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 защищен вызовами Invoke/BeginInvoke для компонентов пользовательского интерфейса.

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

С тех пор я попробовал BackgroundWorker (доступный в OpenNETCF, как и обычный BackgroundWorker в .Net 2.0 и далее), для обработки исключений и сортировки, как в коде ниже. Но с этим я не могу заставить его работать. Вместо этого, когда государство изменено и сообщается обратно в графический интерфейс. Хотя 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

есть подобная дискуссия на http://stackoverflow.com/questions/1862590/how-to-update-gui-with-backgroundworker. возможно, что поможет –

+0

Спасибо ralf. Я прочитал это до публикации. Я думаю, что это близко. Но ProgressUpdated/Completed не помогает мне, потому что код MyClient не знает, что его запускают в фоновом работнике, поэтому он не повышает прогресс, который обновляется. Также GUI должен быть уведомлен об изменениях свойств, то есть состояния. Тем не менее, когда государство изменено, это событие возникает в потоке, отличном от UI. Интересно, должен ли мой клиент быть переписан, чтобы каким-то образом поддержать фоновых работников – JonWillis

ответ

0

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

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

Смежные вопросы