3
votes

I have an ObservableCollection in the ViewModel that add new entries when an ApplicationBar button is pressed in the View. The ListBox which is bound to this ObservableCollection doesnt show the new/updated entry, it does show the items of the collection when the application loads. The ViewModel does implement INotifyPropertyChanged and I do call NotifyPropertyChanged when an item is added to the ObservableCollection (or) set.

ViewModel - based on what is read from the server, new items are added to the observable collection.

public class MainViewModel : INotifyPropertyChanged
{
    private ObservableCollection<SubsViewModel> _itemsUnread;
    public ObservableCollection<SubsViewModel> UnreadItems
    {
        get
        {
            return _itemsUnread;
        }
        set
        {
            _itemsUnread = value;
            NotifyPropertyChanged("Updated");
        }
    }

   void reader_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        switch (e.PropertyName)
        {
            case "Updated":

                Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        UnreadItems.Clear();

                        foreach (ItemViewModel subs in ItemsAll)
                        {
                                ....
                                UnreadItems.Add(subs);
                        }
                    }
                );

                IsDataUpdated = true;

                NotifyPropertyChanged(e.PropertyName);

                break;
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(String propertyName)
    {
        if (null != this.PropertyChanged)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

view - sets the datacontext and itemsource

            <ListBox x:Name="SecondListBox" Margin="0,0,-12,0" ItemsSource="{Binding UnreadItems, Mode=TwoWay}">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Margin="0,0,0,7">
                            <StackPanel Orientation="Horizontal">
                                <TextBlock Text="{Binding ItemTitle}" TextWrapping="NoWrap" Margin="12,0,0,0" Style="{StaticResource PhoneTextLargeStyle}"/>
...

    public MainPage()
    {
        _mainView = new MainViewModel();
        InitializeComponent();

        // Set the data context of the listbox control to the sample data
        DataContext = _mainView;
        this.Loaded += new RoutedEventHandler(MainPage_Loaded);
    }

Any Add/update to the observablecollection in the viewModel is not reflected in the listbox. i've read a bunch of places that notifypropertychanged is the solution, but i already have notifypropertychanged and still see the issue. Any ideas what i'm missing?

From @compoenet_tech's suggestion by adding the new item when the ApplicationBar buttin is pressed. I do see the listbox display the new item

SubsViewModel newitem = new SubsViewModel();
newitem.itemTitle = "test";
newitem.itemCount = test;
_itemssUnread.Add(newitem); test++;

So, doing the Add() outside the Dispatcher Invoke does work. But now the problem is that I get the new list from webservice using a callback, which is where i add the entries into unreaditems collection. which I cannot (??) do outside the dispatcher.

(web service) =callback=> ViewModel =observablecollection=> View

how does viewmodel get notified to update the collection outside a callback where i dont have to use dispather invoke? (or) use dispatcher invoke and not crash through cross thread reference.

Thanks

3
In your UnreadItems property setter you raise a NotifyPropertyChanged for the "Update" named property, you should raise it for UnreadItems. At least i think that's the problem.BigL
I see now why you call it with Update, maybe that's the problem that you handle the property changed event and so it doesn't reach the UI.BigL

3 Answers

2
votes
  1. Please Instantiate the Observable collection before use. In constructor of the MainViewModel write the following code like

    public MainViewModel() { _itemsUnread = new ObservableCollection(); }

  2. Function reader_PropertyChanged is not required to implement.

  3. While calling the NotifyPropertyChanged use the Property Name as parameter like

    public ObservableCollection UnreadItems { get { return _itemsUnread; } set { _itemsUnread = value; NotifyPropertyChanged("UnreadItems"); } }

1
votes

A couple of notes:

1) According to MSDN, ObservableCollection already implements INotificatCollectionChanged for Silverlight, so you shouldn't have to reimplement it.

2) This code in the setter:

        NotifyPropertyChanged("Updated");

has some issues:

a) it will only be executed when the entire collection object itself is changed, not when items within the collection are changed.

b) If a is implemented as you want it to be, then the string parameter should be the property that changed to UnreadItems.

Update

I also suspect (noted in the comments below) that adding the items in the Invoke is causing the notification messages to be lost. I recommend changing the code to add the items directly rather than in the Invoke statement.

0
votes

Your UnreadItems property should be initialized in the constructor with

UnreadItems = new ObservableCollection();