Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF MVVM observable collection not updating GUI

Im designing an MVVM WPF app, and have a ViewModel which has a property called SelectedCustomer, of type Customer. This object has a property called SummaryDetails of type ObservableCollection which renders into a ListView, line by line.

To do this, I have created a separate property on the ViewModel called CustomerSummaryDetails which contains simply a get, that returns the collection contained within the customer I mentioned above.

In the XAML I have bound the ItemsSource to the CustomerSummaryDetails Property.

This was so I didnt have to bind to SelectedCustomer.SummaryDetails which isn't as clean.

The SelectedCustomer property has a get and a set method, and the set calls OnPropertyChanged for the OTHER property, CustomerSummaryDetails, letting the XAML know that the underlying collection has changed and to update.

The problem is though that when I update an item within the collection, it is not reflecting on the GUI, despite all the right events being called. I have stepped in and the set method of the SelectedCustomer is being called, and I then follow the OnPropertyChanged("CustomerSummaryDetails") call which goes into the "get" method of the CustomerSummaryDetails property as expected. I have delved into the value of the returned collection at this point, and the value within the list is the updated value, however nothing is getting reflected on the GUI, so I am puzzled as it seems the GUI is calling the get method to update it on the OnPropertyChanged() call, but it is not reflecting visually.

UPDATE - CODE INCLUDED

Sorry for not including code, I thought it would be easier to just describe but here are the main ViewModel properties

public CustomerSummaryViewModel SelectedCustomer
{
    get { return _selectedCustomer; }
    set
    {
        _selectedCustomer = value;
        OnPropertyChanged("CustomerSummaryDetails");
    }
}

public ObservableCollection<RbcUICustomerSummary> CustomerSummaryDetails
{
    get { return _selectedCustomer.SummaryDetails; }
}

public ItemSummaryViewModel SelectedItem
{
    get { return _selectedItem; }
    set
    {
        _selectedItem = value;
        OnPropertyChanged("SelectedItem");
    }
}

XAML below

    <ListView x:Name="lvCustomerSummary" Margin="10,10,10,10" Background="#F4F8FB" ItemsSource="{Binding CustomerSummaryDetails}" MouseDoubleClick="lvCustomerSummary_MouseDoubleClick" ItemContainerStyle="{StaticResource myHeaderStyleColor}" VirtualizingStackPanel.IsVirtualizing="False" VirtualizingStackPanel.VirtualizationMode="Recycling">
            <ListView.View>
            <GridView ColumnHeaderContainerStyle="{StaticResource myHeaderStyle}">
                    <GridView.Columns>
                    <GridViewColumn Header=""  >
                        <GridViewColumn.CellTemplate>
                            <DataTemplate >
                                <Grid>
                                    <Image Source="{z:ImageStaticResource {Binding IconSelect}}" Width="20" Height="20" />
                                </Grid>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                    <GridViewColumn Width="200" Header="SubCustType" DisplayMemberBinding="{Binding SubCustType}" >
                    </GridViewColumn>
                    <GridViewColumn Width="200" Header="SubCustValue"  DisplayMemberBinding="{Binding SubCustValue}">
                    </GridViewColumn>
                    <GridViewColumn Header=""  >
                        <GridViewColumn.CellTemplate>
                            <DataTemplate >
                                <Grid>
                                    <Image Source="{z:ImageStaticResource {Binding IconFlag}}" Width="20" Height="20" />
                                </Grid>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView.Columns>
            </GridView>
        </ListView.View>
    </ListView>

And finally the Updater method which does the actual update

private void DisplayCustomerComment(string commentEnt)
{            
    if (_queueViewModel.SelectedCustomer == null) return;
        var selCust = _queueViewModel.SelectedCustomer;

    foreach (var t in selCust.SummaryDetails
        .Where(t => t.SubCustType == AppString.CustomerSummary.Comment))
    {
        t.SubCustValue = commentEnt;
        break;
    }

    _queueViewModel.SelectedCustomer = selCust;
}
like image 669
NZJames Avatar asked Oct 30 '12 17:10

NZJames


1 Answers

You're not modifying the ObservableCollection itself (such as adding/removing items) but the items INSIDE that collection. The ObservableCollection is responsible for notifying its own changes, not changes pertaining to its items. You Should NotifyPropertyChange("SubCustValue") in the setter of your SubCustValue.

The change is not being reflected in the UI because when you NotifyPropertyChange() the entire collection, instead of the indiviual property of the individual item, WPF detects it is actually the same instance (the same object reference to the same collection) as before, so nothing seems to have changed.

like image 94
Federico Berasategui Avatar answered Nov 09 '22 04:11

Federico Berasategui