Creating separate series for ViewModel with multiple properties

5 posts, 1 answers
  1. Brandon
    Brandon avatar
    15 posts
    Member since:
    Sep 2017

    Posted 18 Jul 2020 Link to this post

    I have a ViewModel object with multiple properties I want to plot (such as Value1 and Value2 in DualSample below).  I currently have this working with a SeriesProvider that includes a different SeriesDescriptor and ValueBinding for each property, but using the same ItemsSourcePath.

     

    However, I now have some data sets to plot that have a different sample arrangement (such as only having Value1 in SingleSample, and missing Value2).  If I try to use the existing SeriesProvider definition, I get an exception because the SensorValue2Binding doesn't work since the sample is a different type.  I was going to change this to use a SeriesDescriptorSelector, but I don't see how to get multiple series from a single ViewModel  object as before.  The only solution I see is to create separate lists for each property I want to plot, but I'd rather avoid that is I can, mostly to help save on memory usage. 

    ViewModel definition:

    public interface ISample
    {
    }
     
    // Would like to plot this on the same chart as DualSample
    public class SingleSample : ISample
    {
        public Double Value1;
        public DateTime Timestamp;
    }
     
    // This is currently working
    public class DualSample : ISample
    {
        public Double Value1;
        public Double Value2;
        public DateTime Timestamp;
    }
     
    public class Sensor
    {
        // A Sensor might have a set of DualSample values, or a set of SingleSample values, but not both.
        public ObservableCollection<ISample> SensorData;
    }

     

    Currently working solution for DualSample only:

    <!-- Existing solution that working with DualSample only -->
    <telerik:RadCartesianChart.SeriesProvider>
        <telerik:ChartSeriesProvider Source="{Binding SensorList}">
            <!-- When SensorData includes DualSample values, both series descriptors below are used,
            so I get series for both Value1 and Value2 -->
            <telerik:ChartSeriesProvider.SeriesDescriptors>
                <telerik:CategoricalSeriesDescriptor ItemsSourcePath="SensorData">
                    <telerik:CategoricalSeriesDescriptor.Style>
                        <Style TargetType="telerik:LineSeries"
                               BasedOn="{StaticResource {x:Type telerik:LineSeries}}">
                            <Setter Property="ValueBinding"
                                    Value="{StaticResource SensorValue1Binding}"/>
                            <Setter Property="VerticalAxis"
                                    Value="{StaticResource Value1Axis}"/>                                               
                        </Style>
                    </telerik:CategoricalSeriesDescriptor.Style>
                </telerik:CategoricalSeriesDescriptor>
     
                <!-- If I have a SensorData collection of SingleSamples, the SensorValue2Binding values
                and the plot crashes with the following ArgumentException:
                "The value Telerik.Windows.Controls.ChartView.LineSeries is not of type
                Telerik.Windows.Controls.ChartView.CartesianSeries and cannot be used in this generic collection"
                <telerik:CategoricalSeriesDescriptor ItemsSourcePath="SensorData">
                    <telerik:CategoricalSeriesDescriptor.Style>
                        <Style TargetType="telerik:LineSeries"
                               BasedOn="{StaticResource {x:Type telerik:LineSeries}}">
                            <Setter Property="ValueBinding"
                                    Value="{StaticResource SensorValue2Binding}"/>
                            <Setter Property="VerticalAxis"
                                    Value="{StaticResource Value2Axis}"/>
                        </Style>
                    </telerik:CategoricalSeriesDescriptor.Style>
                </telerik:CategoricalSeriesDescriptor>
            </telerik:ChartSeriesProvider.SeriesDescriptors>
        </telerik:ChartSeriesProvider>
    </telerik:RadCartesianChart.SeriesProvider>

     

     

    Attempted solution to work with both DualSample and SingleSample:

    <!-- Attempted solution that I would like to work with both DualSample and SingleSample data sets -->
    <telerik:RadCartesianChart.SeriesProvider>
        <telerik:ChartSeriesProvider Source="{Binding SensorList}">
            <telerik:ChartSeriesProvider.SeriesDescriptorSelector>
                <local:MySeriesDescriptorSelector>
                    <local:MySeriesDescriptorSelector.Value1SeriesDescriptor>
                        <telerik:CategoricalSeriesDescriptor ItemsSourcePath="SensorData">
                            <telerik:CategoricalSeriesDescriptor.Style>
                                <Style TargetType="telerik:LineSeries"
                                       BasedOn="{StaticResource {x:Type telerik:LineSeries}}">
                                    <Setter Property="ValueBinding"
                                            Value="{StaticResource SensorValue1Binding}"/>
                                    <Setter Property="VerticalAxis"
                                            Value="{StaticResource Value1Axis}"/>
                                </Style>
                            </telerik:CategoricalSeriesDescriptor.Style>
                        </telerik:CategoricalSeriesDescriptor>
                    </local:MySeriesDescriptorSelector.Value1SeriesDescriptor>
                    <local:MySeriesDescriptorSelector.Value2SeriesDescriptor>
                        <telerik:CategoricalSeriesDescriptor ItemsSourcePath="SensorData">
                            <telerik:CategoricalSeriesDescriptor.Style>
                                <Style TargetType="telerik:LineSeries"
                                       BasedOn="{StaticResource {x:Type telerik:LineSeries}}">
                                    <Setter Property="ValueBinding"
                                            Value="{StaticResource SensorValue2Binding}"/>
                                    <Setter Property="VerticalAxis"
                                            Value="{StaticResource Value2Axis}"/>
                                </Style>
                            </telerik:CategoricalSeriesDescriptor.Style>
                        </telerik:CategoricalSeriesDescriptor>
                    </local:MySeriesDescriptorSelector.Value2SeriesDescriptor>
                </local:MySeriesDescriptorSelector>
            </telerik:ChartSeriesProvider.SeriesDescriptorSelector>
        </telerik:ChartSeriesProvider>
    </telerik:RadCartesianChart.SeriesProvider>

     

    Any suggestions?  Or is my only option to extract my Value1 and Value2 properties into separate lists?

  2. Martin Ivanov
    Admin
    Martin Ivanov avatar
    2582 posts

    Posted 22 Jul 2020 Link to this post

    Hello Brandon,

    To achieve your requirement, you can create a custom SeriesDescriptor and override its CreateInstanceCore. In the method override, you can get the current ISamle object and based on its concrete type, set the ValueBinding and CategoryBinding methods of the series manually. For example:

    public class CustomCategoricalSeriesDescriptor : CategoricalSeriesDescriptor
    {
    	protected override ChartSeries CreateInstanceCore(object context)
    	{
    		// create a new series and based on the "context" object, set its ValueBinding and CategoryBinding properties
    		return base.CreateInstanceCore(context);
    	}
    }

    I hope this helps.

    Regards,
    Martin Ivanov
    Progress Telerik

  3. Brandon
    Brandon avatar
    15 posts
    Member since:
    Sep 2017

    Posted 27 Jul 2020 in reply to Martin Ivanov Link to this post

    Martin,

     

    I'm still a little confused on how to make to make this work.  The "context" passed into CustomCategoricalSeriesDescriptor is of type Sensor, which contains my collection or either SingleSample or DualSample instances.  In the case of DualSample, I need to create 2 series (one for Value1 data, another for Value2 data).  Do I need 2 separate series descriptor implementations, one that returns a Value1Series and another that returns a Value2Series?

    Also, when CreateInstanceCore() is called, I may not have any data in my collection yet, so I won't know which series I need to return yet.

    Since some cases only need 1 series and others need 2, I assumed I would use the SeriesDescriptorSelector, but I don't see how to use this to select multiple series for a given ViewModel type (1 series for SingleSample collections, 2 series for DualSample collections).

     

    Is there a different way I need to structure my data in order to get the effect I'm looking for?

     

    Thanks,

    Brandon

  4. Answer
    Martin Ivanov
    Admin
    Martin Ivanov avatar
    2582 posts

    Posted 30 Jul 2020 Link to this post

    Hello Brandon,

    Thank you for the additional information. It seems that I misunderstood the requirement. The SeriesProvider cannot be setup as per your needs with the current data models structure. To achieve your requirement, you can change the models a bit. Basically, you can add two collections in the Sensor class - one for Value1 and one for Value2. I've prepared a small example showing this approach. I hope it helps.

    Regards,
    Martin Ivanov
    Progress Telerik

  5. Brandon
    Brandon avatar
    15 posts
    Member since:
    Sep 2017

    Posted 30 Jul 2020 in reply to Martin Ivanov Link to this post

    Martin,

     

    Thanks for your response. The separate collections is what I figured I would have to do, thank you for confirming that.

     

    Brandon

Back to Top