5

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;
}
Antoine Meltzheim
  • 9,579
  • 6
  • 35
  • 41
NZJames
  • 4,963
  • 15
  • 50
  • 100
  • Although you say of type "Customer", what data type is "Customer"... is it a strongly typed class object, a datarow of a datatable, etc? – DRapp Oct 30 '12 at 17:20
  • What is the signature of your CustomerSummaryDetails property? I would suggest that posting some of the source code instead of describing it might be easier too. :-) – AlSki Oct 30 '12 at 17:20
  • What is your binding mode set to? – Bob. Oct 30 '12 at 17:21
  • Did you try setting your Binding Mode=TwoWay in your XAML? – BryanJ Oct 30 '12 at 17:22

1 Answers1

23

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.

Federico Berasategui
  • 43,562
  • 11
  • 100
  • 154