Question

In a previous post I asked how to register a property as DependencyProperty. I got an answer and it works fine.

But now I want to add some Items to this DependencyProperty on a Click. This doesn't work. My code to register the DependencyProperty is:

public static readonly DependencyProperty ChartEntriesProperty = DependencyProperty.Register(
        "ChartEntries", typeof(ObservableCollection<ChartEntry>), typeof(ChartView),
        new FrameworkPropertyMetadata(OnChartEntriesChanged));

    private static void OnChartEntriesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {

    }

The OnChartEntriesChanged-Event is called at the moment I do the Binding from my XAML to my c#-code. But if I add a ChartEntry afterwards (on button-click) the event is not fired.

Does anyone know why?

Was it helpful?

Solution

When you add an item to the ChartEntries collection, you do not actually change that property, so the PropertyChangedCallback isn't called. In order to get notified about changes in the collection, you need to register an additional CollectionChanged event handler:

private static void OnChartEntriesChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var chartView = (ChartView)obj;
    var oldCollection = e.OldValue as INotifyCollectionChanged;
    var newCollection = e.NewValue as INotifyCollectionChanged;

    if (oldCollection != null)
    {
        oldCollection.CollectionChanged -= chartView.OnChartEntriesCollectionChanged;
    }

    if (newCollection != null)
    {
        newCollection.CollectionChanged += chartView.OnChartEntriesCollectionChanged;
    }
}

private void OnChartEntriesCollectionChanged(
    object sender, NotifyCollectionChangedEventArgs e)
{
    ...
}

It would also make sense not to use ObservableCollection<ChartEntry> for the property type, but simply ICollection or IEnumerable instead. This would allow for other implementations of INotifyCollectionChanged in the concrete collection type. See here and here for more information.

OTHER TIPS

OnChartEntriesChanged callback will be called when you will set the new instance of the ObservableCollection. You will have to listen to collection changed as below:

    private static void OnChartEntriesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        ((ObservableCollection<ChartView>)e.OldValue).CollectionChanged -= new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ChartView_CollectionChanged);   
        ((ObservableCollection<ChartView>)e.NewValue).CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(ChartView_CollectionChanged);   
    }

    static void ChartView_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {

    }

Sorry but this won't work as you've detected yourself. The DependencyProperty changed handler does fire only, if the value of the property changes, but in your case it doesn't, as the object reference is still the same. You have to register on the CollectionChanged eventhandler of the provided collection. (this you can do in the propertychanged handler from the dependencyproperty)

The answer from Clemens looks good and helped me a lot. However, in many cases you will want your CollectionChanged event handler to get called also when the entire collection is replaced with another collection. To do this, simply call the CollectionChanged event handler explicitly and directly from the PropertyChanged event handler. The full code would look as follows.

private static void OnChartEntriesChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var chartView = (ChartView)obj;
    var oldCollection = e.OldValue as INotifyCollectionChanged;
    var newCollection = e.NewValue as INotifyCollectionChanged;

    if (oldCollection != null)
    {
        oldCollection.CollectionChanged -= chartView.OnChartEntriesCollectionChanged;
    }

    if (newCollection != null)
    {
        newCollection.CollectionChanged += chartView.OnChartEntriesCollectionChanged;
    }

    // The first parameter below can also be null
    chartView.OnChartEntriesCollectionChanged(newCollection, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}

private void OnChartEntriesCollectionChanged(
    object sender, NotifyCollectionChangedEventArgs e)
{
    ...
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top