views:

33

answers:

1

Hi all
I am trying to add Series binding to the Visifire graphing controls set. To this end i have created a SeriesSource dependency property of time DataSeriesCollection. This is bound in the front end using:

`<Chart SeriesSource={Binding Series} />`  

Problem
When the source changes, the validation callback is called. The value that is passed to this is the correct value, a populated ObservableCollection<something>. Immediately after the validate value is called, the CoerceValue callback is called by something, and the value that is sent to it is an EMPTY ObservableCollection<something>. Bounty will go to anyone who can:

  1. Get the correct populated ObservableCollection<someting> passed to the CoerceValue callback OR
  2. Get the correct value being passed to the OnSeriesSourceChanged callback OR
  3. Explain to me how i can do any of the above :)

Here is the data template for the view:

<DataTemplate DataType="{x:Type vm:ReportViewModel}">
    <Grid Name="rootGrid">
    <visifire:Chart Grid.Row="1" SeriesSource="{Binding Series}">
        <visifire:Chart.AxesX>
                <visifire:Axis Title="X axis" />
        </visifire:Chart.AxesX>
        <visifire:Chart.AxesY>
                <visifire:Axis Title="Y axis" />
        </visifire:Chart.AxesY>
    </visifire:Chart>
    </Grid>
</DataTemplate>

Here is the target Dependency Property

    //Getter and setter for Dependency Property
    public ObservableCollection<DataSeries> SeriesSource
    {
        get { return (ObservableCollection<DataSeries>)GetValue(SeriesSourceProperty); }
        set { SetValue(SeriesSourceProperty, value);           }
    }

    // Using a DependencyProperty as the backing store for SeriesSource.  This enables animation, styling, binding, etc...
    public static readonly DependencyProperty SeriesSourceProperty =
        DependencyProperty.Register("SeriesSource", typeof(ObservableCollection<DataSeries>), typeof(Chart), new UIPropertyMetadata(new ObservableCollection<DataSeries>(), new PropertyChangedCallback(OnSeriesSourceChange), new CoerceValueCallback(CoerceSeries)), new ValidateValueCallback(ValidateSeriesSource));

    //Value validation callback
    private static bool ValidateSeriesSource(object value)
    {
        if (value as ObservableCollection<DataSeries> != null)
            return true;
        return false;
    }

    //Dependency Property Changed callback
    private static void OnSeriesSourceChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        Chart c = d as Chart;
        if (c == null)
            return;
        //This line was causing the issue. It was overriding the setter
        c.SeriesSource = (DataSeriesCollection)e.NewValue;
    }

    //Coerce Value callback
    private static object CoerceSeries(DependencyObject d, object value)
    {
        Chart c = d as Chart;
        var collection = value as System.Collections.ObjectModel.ObservableCollection<Visifire.Charts.DataSeries>;
        foreach (var item in c.Series)
        {
            if (!collection.Contains(item))
                c.Series.Remove(item);
        }
        foreach (var item in collection)
        {
            if (!c.Series.Contains(item))
                c.Series.Add(item);
        }
        return collection;
    }

New information
The value being received by the CoerceValue callback is ALWAYS the first value which that property was set to. So if the first value i pass it is a list with 1 item, it will always coerce the value back to a list with one item!

Edit: found the issue, it was in the property changed callback. Credit goes to Matt for helping me out with the CoerceValue callback

+2  A: 

This may not be the exact problem, but you have logic in your setter. That code isn't going to be executed when the property is assigned via a binding.

Instead of adding logic to your setter, consider using a "coerced" callback which gets called every time a value is assigned to your property. See here for more details about "coerce value" callbacks. They're very similar to what you've done for your "property changed" callback.

Matt Hamilton
Hey Matt, I added the CoerceValue callback, It is getting called whenever the binding is changed, but the Object that is being passed to it is not the object being returned from the source... Tat explains why the propertychanged is never called because the item is always the same, a blank list
TerrorAustralis
see edits for new info
TerrorAustralis