2013-12-03 2 views
1

класса участвуют:Обновление детей Модельное от родителей, воспитывающих событий

  1. Классический MVVM как контейнер для контроля детей.
  2. Детский контроль со своей собственной моделью просмотра (определенная кнопка).
  3. BackgroundWorker опрос через сокет удаленного хоста.

Поведение:

  • Основное применение начинается загрузка Дети управления из списка XML. Каждый ребенок имеет и обработчик события обновления в родительском представлении Модель (мы называем это моделью основного вида), которая обновляет свойство дочернего элемента .
  • Main ViewModel запускает BackgroundWorker
  • BackgroundWorker вызывает метод Socket и использует обратный вызов ViewModel для ответа.
  • Изменения в обратном вызове Основные свойства ViewModel.

Поскольку здесь работает отлично, но потом:

  • Обновленное свойство создает событие в наборе и дети обработчиков начать с их собственным обновлением собственности.
  • При обновлении исключение возникает:

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

Через несколько секунд кнопки обновляются. Я думаю, потому что поток пользовательского интерфейса снова берет управление и обновляет элементы управления. Но есть ли лучший способ справиться с этим?

ответ

1

Чтобы продлить ответ Uebercoder, вы можете не заботиться об элементах управления в вашем просмотреть модель, но вам по-прежнему необходимо маршалирование обновлений фона на основной поток.

Так как в вашем фоне рабочего, или более вероятно, в главном ViewModel, что вам нужно сделать что-то вроде:

Application.Current.Dispatcher.BeginInvoke((Action)(() => { /* update properties */ }))); 
+0

Да, спасибо, это ясно. Но в моем наборе свойств я поднимаю событие, а не прямое обновление свойств. Поскольку он работает для модели родительского представления, становится ясно, что обработчик событий в модели дочернего представления должен повторно присоединиться к потоку пользовательского интерфейса. Но есть ли лучший способ разработать его без трюка Dispatcher? –

+0

Я бы не согласился с тем, что модели просмотра ребенка должны заботиться о маршалинге. Да, именно там он взрывается из-за доступа к управлению, но основная модель обзора - это то, что знает о фоновом потоке, поэтому он должен отвечать за маршалинг. Потребители вашей основной модели не должны знать о ее реализации. Единственный способ сделать это - включить основной опрос фонового потока, но этот вид отрицает его смысл. – GazTheDestroyer

+0

Я отмечаю это как ответ, потому что в настоящее время я использую его и, кажется, самое быстрое решение. –

1

Только принадлежащий поток может обновлять элемент окна (т.е. элементы управления).

Используйте способ Control.Invoke(), чтобы внести изменения в кнопку. У меня есть небольшой вспомогательный класс, который я написал, чтобы позаботиться об этом.

public static class ControlEx 
{ 
    public static void DoSafely(this Control control, Action action) 
    { 
     if (control.InvokeRequired) 
      control.Invoke(new Action(() => 
       { 
        action(); 
        Application.DoEvents(); 
       })); 
     else 
      action(); 
    } 
} 

Так что вместо того, чтобы делать что-то вроде:

button.Text = "new text"; 

из другого потока, я теперь называю

button.DoSafely(() => button.Text = "new text"); 
+0

Я нахожусь в MVVM, я не забочусь о контроле, потому что я обновление свойства ViewModel. –

+0

Как GazTheDestroyer заявила, что вы обновляете свойство на элементе управления или свойство в своей модели, идея такая же. –

+0

Действительно, но таким образом мне нужно вызвать каждую модель детского вида, это неприемлемо. У меня есть подписка на события, чтобы избежать этого. –

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