2012-02-20 14 views
5

Próbowałem pobrać bibliotekę Rx i opracować ją w WPF z MVVM. Zepsułem moją aplikację do komponentów takich jak repozytorium i ViewModel. Moje repozytorium jest w stanie dostarczyć kolekcję studentów jeden po drugim, ale w chwili, gdy próbuję dodać do View ObservableCollection, zgłasza błąd wątku. Poświęciłem trochę wskazówek, żeby to zadziałało.Aktualizowanie obserwowalnej kolekcji z innego wątku

+0

możliwe duplikat [Aktualizacja ObservableCollection w oddzielnych nici] (http://stackoverflow.com/questions/2104614/updating-an-observablecollection-in-a-separate-thread) –

+0

Wypróbuj poniższy link, który zapewnia bezpieczne dla wątków rozwiązanie, które działa z dowolnego wątku i może być powiązane za pośrednictwem wielu wątków interfejsu użytkownika: http://www.codeproject.com/Articles/64936/Multithreaded-ObservableImmutableCollection – Anthony

Odpowiedz

8

Musisz ustawić kontekst synchronizacji poprawnie używając

ObserveOn(SynchronizationContext.Current) 

zobaczyć ten wpis na blogu

http://10rem.net/blog/2011/02/17/asynchronous-web-and-network-calls-on-the-client-in-wpf-and-silverlight-and-net-in-general

dla przykładu.

Oto przykład, który działa dla mnie:

<Page.Resources> 
    <ViewModel:ReactiveListViewModel x:Key="model"/> 
</Page.Resources> 

<Grid DataContext="{StaticResource model}"> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto"/> 
     <RowDefinition/> 
    </Grid.RowDefinitions> 
    <Button Content="Start" Command="{Binding StartCommand}"/> 
    <ListBox ItemsSource="{Binding Items}" Grid.Row="1"/> 
</Grid> 

public class ReactiveListViewModel : ViewModelBase 
{ 
    public ReactiveListViewModel() 
    { 
     Items = new ObservableCollection<long>(); 
     StartCommand = new RelayCommand(Start); 
    } 

    public ICommand StartCommand { get; private set; } 

    private void Start() 
    { 
     var observable = Observable.Interval(TimeSpan.FromSeconds(1)); 

     //Exception: This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread. 
     //observable.Subscribe(num => Items.Add(num)); 

     // Works fine 
     observable.ObserveOn(SynchronizationContext.Current).Subscribe(num => Items.Add(num)); 

     // Works fine 
     //observable.ObserveOnDispatcher().Subscribe(num => Items.Add(num)); 
    } 

    public ObservableCollection<long> Items { get; private set; } 
} 
+0

ta metoda działa, jeśli kod znajduje się w kodzie Xamls, ale potrzebuję ViewModel do dodania obiektu. Moje źródło to usługa Async wywoływana z ViewModel. W tym czasie SynchronitaionContext.Current nie ma żadnej wartości w ViewModel –

+0

Dodałem przykład, który działa dla mnie. Zauważ, że dodałem Rx-Main i Rx-WPF przez NuGet. – Phil

+0

Mój kod jest mniej więcej taki sam, ale moje pobieranie kolekcji i przypisanie odbywa się w Konstruktorze. Używam też Unity do rozwiązania klasy. Dodałem dokładny kod tutaj http://stackoverflow.com/questions/9377290/synchronizationcontext-current-is-null-on-resolving-withunity-in-wpf –

1

Czy Twój kod działa na wątku tła? Ponieważ wpływa na interfejs użytkownika, powiązana obserwacja ObservableCollection może być aktualizowana tylko w wątku UI/Dispatcher.

Zobacz podobną sprawę pod numerem WPF ObservableCollection Thread Safety.

1

Wszelkie zmiany w interfejsie powinny być wykonane przez wątek Dispatcher. Dobrą praktyką, jeśli masz ciągły wątek zmieniający model widoku, jest zmuszenie selektorów właściwości do używania wątku programu rozsyłającego. W takim przypadku upewnij się, że nie zmienisz elementu interfejsu użytkownika w innym wątku.

Spróbuj:

public string Property 
{ 
    set 
    { 
     Dispatcher.BeginInvoke(()=> _property = value) ; 
     OnPropertyChanged("Property"); 
    } 
    get 
    { 
     return _property; 
    } 
} 
Powiązane problemy