2013-04-27 2 views
1

Я не очень разбираюсь в этой теме, так что простите меня, если это не очень понятно.Portable Class Library and ObservableCollection, обновление UI Thread

Я создал портативную библиотеку классов, которая имеет ObservableCollection разделов, и каждый секвенция имеет ObservableCollection of Items.

Обе эти коллекции связаны с пользовательским интерфейсом отдельных приложений Win8 и WP8.

Я пытаюсь найти правильный способ правильно заполнить эти коллекции, чтобы пользовательский интерфейс обновлялся из класса PCL.

Если класс был внутри проекта win8, я знаю, что могу сделать что-то вроде Dispatcher.BeginInvoke, но это не переводит на PCL, и я не смогу его повторно использовать в проекте WP8.

В этой теме (Portable class library equivalent of Dispatcher.Invoke or Dispatcher.RunAsync) Я обнаружил класс SynchroniationContext.

Я прошел в ссылке на SynchroniationContext основного приложения, и когда я заполнить секции я могу сделать это, потому что это только один объект обновляется:

if (SynchronizationContext.Current == _synchronizationContext) 
{ 
    // Execute the CollectionChanged event on the current thread 
    UpdateSections(sections); 
} 
else 
{ 
    // Post the CollectionChanged event on the creator thread 
    _synchronizationContext.Post(UpdateSections, sections); 
} 

Однако, когда я пытаюсь сделать то же самое вещь со статьями, я должен иметь ссылку как на раздел, так и на статью, но метод Post позволяет мне передавать только один объект.

Я попытался использовать лямбда-выражение:

if (SynchronizationContext.Current == _synchronizationContext) 
    { 
// Execute the CollectionChanged event on the current thread 
    section.Items.Add(item); 
} 
else 
{ 
    // Post the CollectionChanged event on the creator thread 
    _synchronizationContext.Post((e) => 
    { 
     section.Items.Add(item); 
    }, null); 
} 

, но я предполагаю, что это не так, как я получаю сообщение об ошибке о том, «выстроил для другого потока».

Итак, где я здесь не так? как я могу правильно обновить обе коллекции с PCL, чтобы оба приложения могли также обновлять свой интерфейс?

большое спасибо!

ответ

2

Трудно сказать, не видя остальной код, но я сомневаюсь, что это имеет какое-либо отношение к переносимым библиотекам классов. Было бы неплохо увидеть подробности об исключении (тип, сообщение и трассировка стека).

То, как вы вызываете Post() с более чем аргументом, выглядит правильно. Что произойдет, если вы удалите отметку if и просто всегда проходите через SynchronizationContext.Post()?

КПП: Я не передаю явно SynchronizationContext. Я предполагаю, что ViewModel создается в потоке пользовательского интерфейса. Это позволяет мне захватить его, как это:

public class MyViewModel 
{ 
    private SynchronizationContext _context = SynchronizationContext.Current; 
} 
+0

Когда я это сделаю, контекст возвращает null. Я должен был сделать новый SynchronizationContext() из приложения, чтобы получить значение, чтобы передать его. Странно, что это не дает мне исключения сразу. он работает несколько раз, прежде чем дать мне эту ошибку на одних и тех же типах данных. но я в конечном итоге отказался и переместил привязки из источника данных непосредственно в viewmodel, который, я считаю, там, где они должны идти в любом случае – SelAromDotNet

1

я рекомендовал бы, что по крайней мере в ваших ViewModels, все публично наблюдаемые изменения состояния (т.е. уведомление об изменении свойств и модификация ObservableCollections) произойдут в потоке пользовательского интерфейса. Я бы порекомендовал делать то же самое с изменениями состояния модели, но может иметь смысл позволить им вносить изменения в разные потоки и маршалировать эти изменения в потоке пользовательского интерфейса в ваших ViewModels.

Для этого, конечно, вы должны иметь возможность переключиться на поток пользовательского интерфейса в переносном коде. Если SynchronizationContext не работает для вас, просто создайте собственную абстракцию для диспетчера (например, IRunOnUIThread).

0

Причина, по которой вы получали ошибку «marshalled on the different thread», заключается в том, что вы не передавали элемент для добавления в список как «состояние» объекта в методе Post (action, state).

Ваш код должен выглядеть следующим образом:

if (SynchronizationContext.Current == _synchronizationContext) 
    { 
// Execute the CollectionChanged event on the current thread 
    section.Items.Add(item); 
} 
else 
{ 
    // Post the CollectionChanged event on the creator thread 
    _synchronizationContext.Post((e) => 
    { 
     var item = (YourItemnType) e; 
     section.Items.Add(item); 
    }, item); 
} 

Если вы сделаете это изменение, ваш код будет работать нормально с PCL.

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