Question

I have a WP8 Pivot application where I am binding data to the XAML:

<phone:LongListSelector Grid.Row="1" Name="llsLocations" ItemsSource="{Binding}" SelectionChanged="LongListSelector_OnSelectionChanged">
    <phone:LongListSelector.ItemTemplate>
        <DataTemplate>
            <Grid Margin="0,0,0,17">
                <Image Source="{Binding Icon}" HorizontalAlignment="Left" Height="54" Width="69" />
                <TextBlock Text="{Binding Location}" HorizontalAlignment="Left" Margin="80,0,0,0" />
                ....
                ....

In the code behind I assign the DataContext like this:

public MainPage()
{
    InitializeComponent();
    DataContext = App.ViewModel.Signs;
}

The ViewModel.Signs object looks like this:

public ObservableCollection<SignsViewModel> Signs { get; set; }
public MainViewModel()
{
    Signs = new ObservableCollection<SignsViewModel>();
}

Within the SignsViewModel object, I have a NotifyPropertyChanged which in theory, should just update the UI whenever the property changes:

private int _id;
public int ID
{
    get { return _id; }
    set
    {
        if (value != _id)
        {
            _id = value;
            NotifyPropertyChanged("ID");
        }
    }
}

I have got a Web Service which populates the Signs object:

private void GetSigns_Completed(object sender, OpenReadCompletedEventArgs e)
{
    using (var sr = new StreamReader(e.Result))
    {
        var data = sr.ReadToEnd();
        var results = JsonConvert.DeserializeObject<GetSignsResponse>(data);
        App.ViewModel.Signs = results.Signs; // <--- This updates the Model
        App.ViewModel.IsDataLoaded = true;
        App.ViewModel.IsWaitingForData = false;
        var storage = new DataStorage();
        storage.SaveSigns(results.Signs);
    }
}

The problem is that when I call the services and when the App.ViewModel.Signs is updated, the User Interface doesn't seem to update itself. What am I doing wrong?

Was it helpful?

Solution

The main thing I see is wrong is with this line, specially where you commented, "This updates the Model":

    var results = JsonConvert.DeserializeObject<GetSignsResponse>(data);
    App.ViewModel.Signs = results.Signs; // <--- This updates the Model
    App.ViewModel.IsDataLoaded = true;

What is most likely happening is that you've broken the reference that your ViewModel.Signs holds to the previous ObservableCollection.

In your MainViewModel constructor, you've already set the Signs property to new ObservableCollection<SignsViewModel>(). However, in the line above, you replaced that reference with results.Signs.

What I would do to pinpoint if this is the problem would be instead of having

    App.ViewModel.Signs = results.Signs; // <--- This updates the Model

Replace it with

    foreach (var sign in results.Signs) {
            App.ViewModel.Signs.Add(sign);
    }

Other things you should consider:

Your SignsViewModel does not need to implement INotifyPropertyChanged (I'm assuming you have), unless you want to have updated changes to the ID property propagate up, i.e. you want the user to be able to Edit the ID value. If you're only displaying them to look at, then it's not necessary to implement INotifyPropertyChanged.

I would not recommend setting the DataContext of the entire Page to anything other than the outermost ViewModel. Rather than

DataContext = App.ViewModel.Signs;

I would choose

DataContext = App.ViewModel;

Then have a

<phone:LongListSelector Grid.Row="1" Name="llsLocations" ItemsSource="{Binding Signs}" SelectionChanged="LongListSelector_OnSelectionChanged">

Which is a bit nicer if you plan to have more functionality.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top