BeginInvoke на ObservableCollection не немедленный - PullRequest
0 голосов
/ 28 апреля 2010

В моем коде я подписываюсь на событие, которое происходит в другом потоке.Каждый раз, когда происходит это событие, я получаю строку, которая публикуется в наблюдаемой коллекции:

    Dispatcher currentDispatcher = Dispatcher.CurrentDispatcher;
    var SerialLog = new ObservableCollection<string>();

    private void hitStation_RawCommandSent(object sender, StringEventArgs e)
    {
        string command = e.Value.Replace("\r\n", "");
        Action dispatchAction = () => SerialLog.Add(command);
        currentDispatcher.BeginInvoke(dispatchAction, DispatcherPriority.Render);
    }

Код ниже находится в моей модели представления (может быть в коде позади, это не имеет значения в этомдело).Когда я вызываю «hittation.PrepareHit», указанное выше событие вызывается пару раз, затем я жду и вызываю «hitStation.HitBall», а указанное выше событие вызывается еще пару раз.

    private void HitBall()
    {
        try
        {
            try
            {
                Mouse.OverrideCursor = Cursors.Wait;

                //prepare hit
                hitStation.PrepareHit(hitSpeed);

                Thread.Wait(1000);
                PlayWarning();

                //hit
                hitStation.HitBall(hitSpeed);
            }
            catch (TimeoutException ex)
            {
                MessageBox.Show("Timeout hitting ball: " + ex.Message);
            }
        }
        finally
        {
            Mouse.OverrideCursor = null;
        }
    }

У меня проблема в том, что ListBox, связанный с моим SerialLog, обновляется только после завершения метода HitBall.Я ожидал увидеть кучу обновлений от PrepareHit, паузу и еще кучу обновлений от HitBall.

Я пробовал пару аргументов DispatcherPriority, но, похоже, они не имеют никакого эффекта.

Ответы [ 3 ]

4 голосов
/ 28 апреля 2010

Я думаю, что вы блокируете себя.

Поток пользовательского интерфейса ожидает в Thread.Wait, BeginInvoke отправляет действие дипатчеру, однако поток пользовательского интерфейса занят ожидания. Вот почему обновления пользовательского интерфейса выполняются только после завершения HitBall, то есть когда обработка потока пользовательского интерфейса завершается.

Чтобы обойти это, вы должны запустить код метода HitBall в другом потоке, освобождая пользовательский интерфейс:

 private void HitBall() 
 { 
     try {

         Mouse.OverrideCursor = Cursors.Wait;
         Dispatcher dispatcher = Dispatcher.CurrentDispatcher;

         Action hitOperations = () =>
         {
             hitStation.PrepareHit(hitSpeed);

             Thread.Wait(1000);

             //Only needed if PlayWarning needs access to UI Thread
             dispatcher.Invoke(() => PlayWarning());

             hitStation.HitBall(hitSpeed);

             dispatcher.Invoke(() => Mouse.OverrideCursor = null);
          };

          //Free the UI from work, start operations in a background thread
          hitOperations.BeginInvoke(null, null);

      }
      catch (TimeoutException ex)
      {
          MessageBox.Show("Timeout hitting ball: " + ex.Message);
      }
 }

Также, если предполагалось использовать Thread.Wait (1000) для ожидания событий для обновления пользовательского интерфейса, в этой реализации это больше не требуется.

1 голос
/ 28 апреля 2010

Может ли быть что-то столь же простое, как необходимость вызвать событие PropertyChanged в вашей ViewModel?

0 голосов
/ 28 апреля 2010

Вероятно, вы не увидите обновлений с PrepareHit, если нет переключения контекста и нет гарантии, когда произойдет переключение контекста (если вы не заблокируете текущий поток и это не увеличит вероятность того, что произойдет переключение контекста).

Как уже упоминалось в iCe, если вы делаете это в потоке пользовательского интерфейса, возможно, вы блокируете свой пользовательский интерфейс. Ваш пользовательский интерфейс блокируется / останавливается, когда вы звоните Thread.Wait? Если это не так, продолжайте читать ниже:

Обновление:
Я не могу придумать ничего, что не могло бы поставить под угрозу параллелизм ... без ущерба для параллелизма вы могли бы попытаться увеличить приоритет BeginInvoke: http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx

currentDispatcher.BeginInvoke(dispatchAction, DispatcherPriority.Send);

Кстати, похоже, Render приоритет ниже, чем Normal приоритет:

Render Значение перечисления равно 7. Операции обрабатываются одновременно приоритет как рендеринг.

DataBind The значение перечисления равно 8. Операции обрабатывается с тем же приоритетом, что и данные связывание.

Normal Значение перечисления 9. Операции обрабатываются в нормальный приоритет. Это типичный приоритет приложения.

Отправить значение перечисления равно 10. Операции обрабатываются раньше других асинхронные операции. Это самый высокий приоритет.

...