0
votes

I'm pretty new to wpf and mvvm so this may be a easy question but I'm hoping someone can explain it to me. I have a class in my model that all it does is polls processes and if it see that "calc" is running it adds it process id to a List. If you close calc.exe it removes it from the List. If the List changes it fires and event. In my ViewModel i subscribe to that event and update my property that fires off PropertyChanged. Now if my Property is a List in the view model then my binding in my view does not update correctly. If I changed my List to an ObservableCollection in my Model and ViewModel then i get a cross thread issue. However, if i leave my List in my model and change my property in my ViewModel to a ObservableCollection and copy the values of the the list into an observable collection everything works as expected.... I don't get it, do i really need to do the copy to get the binding in my ListBox to work properly?

3

3 Answers

0
votes

Take a look at the DispatcherNotifiedObservableCollection that Cinch implements. It will automatically use the Dispatcher if need be. Read this article to see the code for it:

http://www.codeproject.com/KB/WPF/CinchIII.aspx#ObsCol

0
votes

You need to update the observable collection from the dispatch thread.

Something like (not technically/syntactically correct, but psuedo-close)

Dispatcher.BeginInvoke( () => theList.Add( theThing ) );
0
votes

A better way to achieve this functionality, is expose the Model via a property in the ViewModel, and bind the ListBox to Model.ObservableList. And use John's suggestion when adding and removing items to this list. This will not require you to copy the values from list to an observablecollection.

So your viewModel code would like

    public class ViewModel
    { 
        public Model Model { get { return _model; } }
    }

The binding in xaml:

    <ListBox ItemsSource=Model.ObservableList/>

where the ObservableList property returns your ObservableCollection.

As all UI elements in WPF have thread affinity (to the Dispatcher thread), any updates to the UI should be marshaled via the Dispatcher. You can marshal calls via the Dispatcher, using Dispatcher.Invoke. In this case, your view, viewModel and Model reside in the Dispatcher thread, so any call to update the UI via the viewModel or Model, would require you to call Dispatcher.Invoke.