1

I have a class, "MainViewModel" that includes an Observable Collection of ColourMappingViewModel, and references out to two other ViewModels, one which is used to update the ColourMappingViewModels (ColourControllerViewModel), and one which contains a CollectionView which is used to display a particular subset of these ColourMappingViewModels (ColourSelectionViewModel). Both these classes are passed the ObservableCollection to bind to.

ColourMappingViewModel has two properties: The Color , and the Type.

public class ColourMappingViewModel : ViewModel,
{
    public Color TextColour
    {
        get
        {
            return (Color)ColorConverter.ConvertFromString(_colourMapping.TextColour);
        }
        set
        {
            _colourMapping.TextColour = value.ToString().Remove(1, 2);
            OnPropertyChanged();
        }
    }


    public ColourMappingUsageType Type
    {
        get
        {
            return _colourMapping.Usage;
        }
        set
        {                
            _colourMapping.Usage = value;
            OnPropertyChanged()
        }
    }

}

ColourController includes a DataGrid, with the Type column including a ComboBox which binds to a collection of the enum types and the "Type" property like so:

  ItemsSource="{Binding Types, Mode=OneWay}"
  SelectedValue="{Binding Type, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" 

And similarly, another ComboBox containing the ColourList, bound like so:

ItemsSource="{Binding DataContext.ColoursList,
             RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type view:ColourController}}}"
             SelectedItem="{Binding BackgroundColour, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"

The CollectionView on ColourSelectionViewModel filters the list based on the value of "Type", and I have another ComboBox on my ColourSelection view that is bound to this CollectionView.

Now. If I update the "TextColour" of in the ColourController, this is reflected in the ColourSelector - I can see the changes.

If I update the 'Type', though, the whole thing falls over with a StackOverflowException due to "OnPropertyChanged()" being repeatedly called. My question is, why!?

jimbo
  • 603
  • 9
  • 27

1 Answers1

1

Update your code to:

public Color TextColour
{
    get
    {
        //it would be faster to convert in the set, not in the get
        //get is called more often
        return (Color)ColorConverter.ConvertFromString(_colourMapping.TextColour);
    }
    set
    {
        var converted = value.ToString().Remove(1, 2);
        if (_colourMapping.TextColour == converted) return;
        _colourMapping.TextColour = converted;
        OnPropertyChanged();
    }
}


public ColourMappingUsageType Type
{
    get
    {
        return _colourMapping.Usage;
    }
    set
    {                
        if (_colourMapping.Usage == value) return;
        _colourMapping.Usage = value;
        OnPropertyChanged()
    }
}
Andrei Tătar
  • 7,872
  • 19
  • 37
  • Good spot on the converting in the set (It's not my code, honest!) and that stops the recursion of OnPropertyChanged(), but my CollectionView isn't updated with the new Type information. But maybe I need to ensure Refresh is invoked on it. – jimbo Jun 19 '15 at 10:55
  • @jimbo. Yes, collection views (of non observable collections) need to be refreshed when their source items have changed. – Andrei Tătar Jun 19 '15 at 10:57
  • It's a collection view of an observable collection though - the collection is set to filter on 'Type', but the 'Type' doesn't seem to be updating in the collection view so the combobox isn't updating. – jimbo Jun 19 '15 at 12:29
  • If the filter does not change (but it's rule does) and the collection source remains the same, it has no way of knowing that is should refresh the items other than calling Refresh. – Andrei Tătar Jun 19 '15 at 12:39