This is a migrated thread and some comments may be shown as answers.

Binding properties of a composite objects to HighBinding and LowBinding in RangeBarSerires

6 Answers 85 Views
Chart
This is a migrated thread and some comments may be shown as answers.
This question is locked. New answers and comments are not allowed.
Alex
Top achievements
Rank 1
Alex asked on 16 Aug 2014, 10:35 PM
In my application I am dealing a lot with objects that have a concept of a range, for that reason I abstracted the logic related to ranges into a separate class. Below is the skeleton of the class, though in my application this class does much more (ex. checks for overlapping, containment, equality, uniqueness,  etc).

public class Range : INotifyPropertyChanged
    {
        private int high;
        private int low;
 
        public Range(int low, int high)
        {
            this.low = Low;
            this.high = High;
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        public int High
        {
            get
            {
                return this.high;
            }
 
            set
            {
                this.high = value;
                this.OnPropertyChanged();
            }
        }
 
        public int Low
        {
            get
            {
                return this.low;
            }
 
            set
            {
                this.low = value;
                this.OnPropertyChanged();
            }
        }
 
        [NotifyPropertyChangedInvocator]
        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

My business logic classes include this Range class and rely on this class to perform range related operations, for example:

public class HeartRateZone : INotifyPropertyChanged
    {
        private string name;
        private bool isSelected;
 
        private Range range;
 
        public HeartRateZone(string name, Range range)
        {
            this.Range = range;
            Name = name;
        }
 
        public event PropertyChangedEventHandler PropertyChanged;
 
        public string Name
        {
            get
            {
                return this.name;
            }
 
            set
            {
                this.name = value;
                this.OnPropertyChanged();
            }
        }
 
        public bool IsSelected
        {
            get
            {
                return this.isSelected;
            }
 
            set
            {
                this.isSelected = value;
                this.OnPropertyChanged();
            }
        }
 
        public Range Range
        {
            get
            {
                return this.range;
            }
 
            set
            {
                this.range = value;
                this.OnPropertyChanged();
            }
        }
 
        [NotifyPropertyChangedInvocator]
        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            var handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(propertyName));
            }
        }
    }
}

I would like to chart my business objects using RangeBarSeries, and my expectation was that I could bind HighBinding and LowBinding properties of the RangeBarSeries to the corresponding High and Low properties of my Range class (see below) embedded in my business logic classes. 
Note: DataPointsCollection in the example below, is of type ObservableCollection<HeartRateZones>, where HeartRateZone contains Range class.
<telerikChart:RangeBarSeries x:Name="BarSeries"
               CategoryBinding="Name"                        
               ItemsSource="{Binding ElementName=HeartRateZoneChartControl, Path=DataPointsCollection}"
               Canvas.ZIndex="2"
               HighBinding="Range.High"
               LowBinding="Range.Low">

Unfortunately, I am getting this exception:

{System.ArgumentException: Could not find property 'Range.High' for type 'ZonesVisualization.Controls.HeartRateZone'
   at Telerik.Windows.DynamicHelper.CreatePropertyValueGetter(Type type, String propertyName)
   at Telerik.Windows.Controls.PropertyNameDataPointBinding.GetValue(Object instance)
   at Telerik.Windows.Controls.RangeSeriesBaseDataSource.InitializeBinding(DataPointBindingEntry binding)
   at Telerik.Windows.Controls.ChartSeriesDataSource.GenerateDataPoint(Object dataItem, Int32 index)
   at Telerik.Windows.Controls.ChartSeriesDataSource.BindCore()
   at Telerik.Windows.Controls.ChartSeriesDataSource.Bind()
   at Telerik.Windows.Controls.ChartSeriesDataSource.Rebind(Boolean itemsSourceChanged, IEnumerable newSource)
   at Telerik.Windows.Controls.ChartSeriesDataSource.set_ItemsSource(IEnumerable value)
   at Telerik.Windows.Controls.ChartSeries.OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
   at System.Windows.DependencyObject.RaisePropertyChangeNotifications(DependencyProperty dp, Object oldValue, Object newValue)
   at System.Windows.DependencyObject.UpdateEffectiveValue(DependencyProperty property, EffectiveValueEntry oldEntry, EffectiveValueEntry& newEntry, ValueOperation operation)
   at System.Windows.Dependen

Attaching a project that reproduces this issue (renamed zip to jpg).
Thanks.
Alex.

6 Answers, 1 is accepted

Sort by
0
Rosy Topchiyska
Telerik team
answered on 19 Aug 2014, 02:32 PM
Hello Alex,

Thank you for contacting us.

Unfortunately, the PropertyNameDataPointBinding binding, used when binding the chart series to business objects, does not work with nested properties. You will have to move the High and Low properties directly to the HeartRateZone class. I have modified your project to demonstrate how you can do this.

I hope this helps. Please, let us know if you have further questions.

Regards,
Rosy Topchiyska
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Alex
Top achievements
Rank 1
answered on 24 Aug 2014, 08:22 PM
Rosy, 
Thanks for your response, though I have to say that it is not what I hoped for. This is a non-starter for me. I spent a lot of time and effort in isolating the Range functionality into a separate class and also built several User Controls that take range as the input, now I have to break this encapsulation, which I am not willing to do.
BTW, Syncfusion's HiLo Chart supports this behavior out of the box - something for your dev team to consider.
Thanks
Alex.
0
Ivaylo Gergov
Telerik team
answered on 26 Aug 2014, 10:05 AM
Hello Alex,

Thank you for your feedback.

I reviewed your scenario and I would like to suggest how to achieve this. As the PropertyNameDataPointBinding class is public, you can create a class which derives from it and override its GetValue(object instance) method. In this method you can simply assign the Range value to the instance object and execute the base method. Here's an example:
public class RangeDataPointBinding : PropertyNameDataPointBinding
{
    public override object GetValue(object instance)
    {
        instance = (instance as HeartRateZone).Range;
 
        return base.GetValue(instance);
    }
}

For your convenience, I have also attached a sample project to demonstrate this approach.

Please, let me know if this suits your needs.

Regards,
Ivaylo Gergov
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Alex
Top achievements
Rank 1
answered on 28 Aug 2014, 02:40 AM
Ivaylo, thank you so much for your suggestion - I am almost up and running.

After implementing the approach you provided, I am now facing a similar but different issue, where I need to reference a nested class inside my PointTemplate (see below: trying to bind Text="{Binding Path=HeartRateRange.UpperRange}"
Is there a way to use a nested class inside a PointTemplate?
Thanks 
Alex.

<telerikChart:RangeBarSeries.PointTemplate>
                    <DataTemplate>
                        <Border
                            BorderBrush="{Binding IsSelected, Converter={StaticResource BoolToAccentColorConverter}}"
                            BorderThickness="2">
                            <Grid Background="{StaticResource PhoneForegroundBrush}">
                                <Canvas VerticalAlignment="Top">
                                    <TextBlock
                                            Text="{Binding Path=HeartRateRange.Value.UpperRange, Mode=TwoWay}"
                                            Canvas.Left="10"
                                            Canvas.Top="-28"
                                            Foreground="{StaticResource AnnotationsPointForeground}"/>
                                </Canvas>
                                <Canvas VerticalAlignment="Bottom">
                                    <TextBlock
                                            Text="{Binding Path=HeartRateRange.Value.LowerRange, Mode=TwoWay}"
                                            Canvas.Left="7"/>
                                </Canvas>
                            </Grid>
                        </Border>
                    </DataTemplate>
0
Accepted
Ves
Telerik team
answered on 01 Sep 2014, 11:23 AM
Hi Alex,

You can do this. The DataContext would be the DataPoint object. It contains the information needed to display the corresponding item. In this case it is a RangeDataPoint object. It holds High and Low values as well as a reference to the original data item, through the DataItem property. So, in the path you would need to start with DataItem and then add the path. E.g. if the series items source is a collection of HeartRateRange objects, then your binding might look like this:

<TextBlock
    Text="{Binding Path=DataItem.HeartRateRange.Value.UpperRange}"
    Canvas.Left="10"
    Canvas.Top="-28"
    Foreground="{StaticResource AnnotationsPointForeground}"/>

As a side note -- it seems you might get rid of that Mode=TwoWay.

Best regards,
Ves
Telerik
 

Check out the Telerik Platform - the only platform that combines a rich set of UI tools with powerful cloud services to develop web, hybrid and native mobile apps.

 
0
Alex
Top achievements
Rank 1
answered on 07 Sep 2014, 09:17 PM
Thanks so much for your help. This is exactly what I was looking for.
Tags
Chart
Asked by
Alex
Top achievements
Rank 1
Answers by
Rosy Topchiyska
Telerik team
Alex
Top achievements
Rank 1
Ivaylo Gergov
Telerik team
Ves
Telerik team
Share this question
or