Do you guys have an example of DateTime data virtualization?
My data is updating live. I need a way to update visual ranges every second as data comes in and scroll backwords with the scroll bar through historical data.
I have 2 observable collections one for the total data and one for the visible data.
In the example project I see it updating using the ActualVisiualRange event on the telerik:LinearAxis but as far as event args I only see e.Newrange.Minimum/Maximum which seems to be the Y range not the X...
Insight would be helpful as im not sure how to update the X data which are DateTimes in this event...
7 Answers, 1 is accepted
Hi Maxwell,
I guess you mean the following example: https://github.com/telerik/xaml-sdk/blob/master/ChartView/WPF/DataVirtualization
If this is your case, keep in mint that in the example, the ActualVisibleRange event handler is attached to the HorizontalAxis (usually annotated as the X axis) of the chart. This means that the X range is updated when you scroll, not the Y one.
The example shows a LinearAxis, but you can use the same approach also with a DateTimeContinuousAxis, because it has the ActualVisibleRange event too.
Regards,
Martin Ivanov
Progress Telerik
Hello Maxwell,
The ActualVisibleRangeChanged event of DateTimeContinuousAxis is fired when the chart is scrolled. I've updated the DataVirtualization SDK example to show this approach. Can you please give it a try and let me know if it helps?
Regards,
Martin Ivanov
Progress Telerik
I still cannot get the event to fire. I am binding to a series provider rather than a viewmodel if that makes a difference.
Here is my xaml
<!--Converters-->
<converters:BoolToVisibilityConverter x:Key="visibilityConverter"/>
<converters:NewLineStrokeSelector x:Key="lineStrokeSelector"/>
<converters:RuntimeFontWeightConverter x:Key="fontWeightConverter"/>
<converters:RuntimeFontStyleConverter x:Key="fontStyleConverter"/>
<converters:RuntimeDecorationConverter x:Key="decorationConverter"/>
<converters:TickMarkConverter x:Key="tickMarkConverter"/>
<converters:ReturnConverter x:Key="returnConverter"/>
<converters:LineStyleConverter x:Key="lineStyleConverter"/>
<converters:ChartLineStyleConverter x:Key="chartLineStyleConverter"/>
<converters:ScatterPointDefaultStyleConverter x:Key="scatterPointDefaultStyleConverter"/>
<!--Data Templates for axis ticks-->
<DataTemplate x:Key="visibleTicks">
<Rectangle StrokeThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="{Binding DataContext.Object.Font.Color, ElementName=ChartControl, Converter={StaticResource lineStrokeSelector}}"/>
</DataTemplate>
<DataTemplate x:Key="hiddenTicks">
<Rectangle StrokeThickness="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Stroke="{Binding DataContext.Object.Font.Color, ElementName=ChartControl, Converter={StaticResource lineStrokeSelector}}"/>
</DataTemplate>
<!--Chart control template-->
<ControlTemplate x:Name="ChartTemplate" x:Key="chartTemplate" TargetType="{x:Type src:DSChartControl}">
<!-- Border handles fill color for entire object -->
<Border BorderBrush="Black" BorderThickness="0" Background="{Binding Path=Object.FillColor, Converter={StaticResource lineStrokeSelector}}">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- Title above the chart -->
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Text="{Binding Path=Object.Title}" FontSize="{Binding Path=Object.Font.Size}" Foreground="{Binding Path=Object.Font.Color, Converter={StaticResource lineStrokeSelector}}"
FontFamily="{Binding Path=Object.Font.FontFamily}" FontWeight="{Binding Path=Object.Font.Weight, Converter={StaticResource fontWeightConverter}}"
HorizontalAlignment="Center" TextDecorations="{Binding Path=Object.Font.Decoration, Converter={StaticResource decorationConverter}}"
FontStyle="{Binding Path=Object.Font.Style, Converter={StaticResource fontStyleConverter}}"
Visibility="{Binding Path=Object.ShowTitle, Converter={StaticResource visibilityConverter}}"/>
<!--Legend to the left of the chart-->
<telerik:RadLegend Grid.Row="1" Grid.Column="0" Items="{Binding LegendItems, ElementName=ChartControl}" BorderBrush="Black" BorderThickness="1"
VerticalAlignment="Top" Margin="4" MinWidth="75"
Foreground="{Binding DataContext.Object.Font.Color, ElementName=ChartControl, Converter={StaticResource lineStrokeSelector}}"
FontFamily="{Binding Path=Object.Font.FontFamily}" FontWeight="{Binding Path=Object.Font.Weight, Converter={StaticResource fontWeightConverter}}"
FontStyle="{Binding Path=Object.Font.Style, Converter={StaticResource fontStyleConverter}}"
Visibility="{Binding Path=Object.ShowLegend, Converter={StaticResource visibilityConverter}}">
</telerik:RadLegend>
<telerik:RadCartesianChart x:Name="ChartControl" Grid.Row="1" Grid.Column="1">
<telerik:RadCartesianChart.Behaviors>
<telerik:ChartPanAndZoomBehavior ZoomMode="Horizontal" PanMode="Horizontal" DragMode="Pan" DragToZoomThreshold="10" />
<telerik:ChartTrackBallBehavior SnapMode="AllClosePoints" TrackInfoUpdated="ChartTrackBallBehavior_TrackInfoUpdated" ShowTrackInfo="{Binding Path=Object.TrackBall}"/>
</telerik:RadCartesianChart.Behaviors>
<telerik:RadCartesianChart.TrackBallInfoStyle>
<Style TargetType="telerik:TrackBallInfoControl">
<!--<Setter Property="Header" Value="{Binding Datapoint.Category}"/>-->
</Style>
</telerik:RadCartesianChart.TrackBallInfoStyle>
<telerik:RadCartesianChart.Resources>
</telerik:RadCartesianChart.Resources>
<!-- Controls the chart's grid properties -->
<telerik:RadCartesianChart.Grid>
<telerik:CartesianChartGrid MajorLinesVisibility="XY" Visibility="{Binding Path=Object.ShowGrid, Converter={StaticResource visibilityConverter}}"
MajorXLineDashArray="{Binding Path=Object.GridStyle, Converter={StaticResource lineStyleConverter}}"
MajorYLineDashArray="{Binding Path=Object.GridStyle, Converter={StaticResource lineStyleConverter}}">
<!-- Sets the grid line colors -->
<telerik:CartesianChartGrid.MajorYLineStyle>
<Style TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="{Binding Path=Object.GridColor, Converter={StaticResource lineStrokeSelector}}"/>
</Style>
</telerik:CartesianChartGrid.MajorYLineStyle>
<telerik:CartesianChartGrid.MajorXLineStyle>
<Style TargetType="{x:Type Line}">
<Setter Property="Stroke" Value="{Binding Path=Object.GridColor, Converter={StaticResource lineStrokeSelector}}"/>
</Style>
</telerik:CartesianChartGrid.MajorXLineStyle>
</telerik:CartesianChartGrid>
</telerik:RadCartesianChart.Grid>
<!--Defines the series type for the horizontal axis-->
<telerik:RadCartesianChart.HorizontalAxis>
<telerik:DateTimeContinuousAxis x:Name="xAxis" ShowLabels="{Binding Path=Object.ShowXLabels}" MajorStepUnit="Second"
MajorStep="5"
PlotMode="OnTicks"
SmartLabelsMode="SmartStep"
LabelFormat="HH:mm:ss.fffffff"
Minimum="{Binding Path=Object.TimeMin}"
Maximum="{Binding Path=Object.TimeMax}"
ActualVisibleRangeChanged="DateTimeContinuouseAxis_ActualVisibleRangeChanged">
<!--Minimum="{Binding Path=Object.TimeMin}"
Maximum="{Binding Path=Object.TimeMax}">-->
<telerik:DateTimeContinuousAxis.MajorTickTemplate >
<MultiBinding Converter="{StaticResource tickMarkConverter}">
<Binding Path="Object.ShowXTicks"/>
<Binding Source="{StaticResource visibleTicks}"/>
<Binding Source="{StaticResource hiddenTicks}"/>
</MultiBinding>
</telerik:DateTimeContinuousAxis.MajorTickTemplate>
</telerik:DateTimeContinuousAxis>
</telerik:RadCartesianChart.HorizontalAxis>
<telerik:RadCartesianChart.VerticalAxis>
<telerik:LinearAxis x:Name="yAxis" Minimum="{Binding Path=Object.MinimumValue}"
Maximum="{Binding Path=Object.MaximumValue}" ShowLabels="{Binding Path=Object.ShowYLabels}">
<telerik:LinearAxis.MajorTickTemplate>
<MultiBinding Converter="{StaticResource tickMarkConverter}">
<Binding Path="Object.ShowYTicks"/>
<Binding Source="{StaticResource visibleTicks}"/>
<Binding Source="{StaticResource hiddenTicks}"/>
</MultiBinding>
</telerik:LinearAxis.MajorTickTemplate>
</telerik:LinearAxis>
</telerik:RadCartesianChart.VerticalAxis>
<!--Define a series provider that handles dynamically created data series-->
<telerik:RadCartesianChart.SeriesProvider>
<!--Binds to a collection of data series in the code behind-->
<telerik:ChartSeriesProvider x:Name="chartProvider" Source="{Binding Object.YAxes}">
<telerik:ChartSeriesProvider.SeriesDescriptorSelector>
<converters:CustomSeriesDescriptorSelector>
<converters:CustomSeriesDescriptorSelector.LineTimeDescriptor>
<telerik:CategoricalSeriesDescriptor CategoryPath="Time" ValuePath="PointValue" ItemsSourcePath="VisibleTimeData">
<telerik:CategoricalSeriesDescriptor.Style>
<Style TargetType="telerik:LineSeries">
<Setter Property="TrackBallInfoTemplate">
<Setter.Value>
<DataTemplate>
<StackPanel >
<StackPanel Orientation="Vertical">
<TextBlock>
<TextBlock.Text>
<MultiBinding StringFormat=' {0} {1} '>
<Binding Path=" DataPoint.DataItem.Label"/>
<Binding Path="DataPoint.Value"/>
</MultiBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Stroke" Value="{Binding Path=Color, Converter={StaticResource lineStrokeSelector}}" />
<Setter Property="StrokeShapeStyle" Value="{Binding Path=LineStyle, Converter={StaticResource chartLineStyleConverter}}"/>
<Setter Property="LegendSettings">
<Setter.Value>
<telerik:SeriesLegendSettings Title="{Binding Label}" />
</Setter.Value>
</Setter>
<Setter Property="RenderOptions">
<Setter.Value>
<telerik:XamlRenderOptions DefaultVisualsRenderMode="Separate"/>
</Setter.Value>
</Setter>
<Setter Property="HorizontalAxis">
<Setter.Value>
<telerik:DateTimeContinuousAxis x:Name="xAxis" ShowLabels="{Binding Path=Object.ShowXLabels}" MajorStepUnit="Second"
MajorStep="5"
PlotMode="OnTicks"
SmartLabelsMode="SmartStep"
LabelFormat="HH:mm:ss.fffffff"
Minimum="{Binding Path=Object.TimeMin}"
Maximum="{Binding Path=Object.TimeMax}"
ActualVisibleRangeChanged="DateTimeContinuouseAxis_ActualVisibleRangeChanged">
<telerik:DateTimeContinuousAxis.MajorTickTemplate >
<MultiBinding Converter="{StaticResource tickMarkConverter}">
<Binding Path="Object.ShowXTicks"/>
<Binding Source="{StaticResource visibleTicks}"/>
<Binding Source="{StaticResource hiddenTicks}"/>
</MultiBinding>
</telerik:DateTimeContinuousAxis.MajorTickTemplate>
</telerik:DateTimeContinuousAxis>
</Setter.Value>
</Setter>
</Style>
</telerik:CategoricalSeriesDescriptor.Style>
</telerik:CategoricalSeriesDescriptor>
</converters:CustomSeriesDescriptorSelector.LineTimeDescriptor>
<converters:CustomSeriesDescriptorSelector.ScatterTimeDescriptor>
<telerik:CategoricalSeriesDescriptor CategoryPath="Time" ValuePath="PointValue" ItemsSourcePath="VisibleTimeData">
<telerik:CategoricalSeriesDescriptor.Style>
<Style TargetType="telerik:PointSeries">
<Setter Property="DefaultVisualStyle">
<Setter.Value>
<MultiBinding Converter="{StaticResource scatterPointDefaultStyleConverter}">
<Binding Path="Symbol"/>
<Binding Path="Color"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="LegendSettings">
<Setter.Value>
<telerik:SeriesLegendSettings Title="{Binding Label}" />
</Setter.Value>
</Setter>
<Setter Property="RenderOptions">
<Setter.Value>
<telerik:Direct2DRenderOptions DefaultVisualsRenderMode="Batch"/>
</Setter.Value>
</Setter>
<Setter Property="HorizontalAxis">
<Setter.Value>
<telerik:DateTimeContinuousAxis x:Name="xAxis" ShowLabels="{Binding Path=Object.ShowXLabels}" MajorStepUnit="Second"
MajorStep="5"
PlotMode="OnTicks"
SmartLabelsMode="SmartStep"
LabelFormat="HH:mm:ss.fffffff"
Minimum="{Binding Path=Object.TimeMin, Mode=TwoWay}"
Maximum="{Binding Path=Object.TimeMax}"
ActualRangeChanged="DateTimeContinuouseAxis_ActualVisibleRangeChanged">
<!--Minimum="{Binding Path=Object.TimeMin}"
Maximum="{Binding Path=Object.TimeMax}">-->
<telerik:DateTimeContinuousAxis.MajorTickTemplate >
<MultiBinding Converter="{StaticResource tickMarkConverter}">
<Binding Path="Object.ShowXTicks"/>
<Binding Source="{StaticResource visibleTicks}"/>
<Binding Source="{StaticResource hiddenTicks}"/>
</MultiBinding>
</telerik:DateTimeContinuousAxis.MajorTickTemplate>
</telerik:DateTimeContinuousAxis>
</Setter.Value>
</Setter>
</Style>
</telerik:CategoricalSeriesDescriptor.Style>
</telerik:CategoricalSeriesDescriptor>
</converters:CustomSeriesDescriptorSelector.ScatterTimeDescriptor>
<converters:CustomSeriesDescriptorSelector.LineXYDescriptor>
<telerik:ScatterSeriesDescriptor XValuePath="X" YValuePath="Y" ItemsSourcePath="NumericData">
<telerik:ScatterSeriesDescriptor.Style>
<Style TargetType="telerik:ScatterLineSeries">
<Setter Property="Stroke" Value="{Binding Path=Color, Converter={StaticResource lineStrokeSelector}}" />
<Setter Property="StrokeShapeStyle" Value="{Binding Path=LineStyle, Converter={StaticResource chartLineStyleConverter}}"/>
<Setter Property="LegendSettings">
<Setter.Value>
<telerik:SeriesLegendSettings Title="{Binding Label}" />
</Setter.Value>
</Setter>
<Setter Property="RenderOptions">
<Setter.Value>
<telerik:Direct2DRenderOptions DefaultVisualsRenderMode="Batch"/>
</Setter.Value>
</Setter>
<Setter Property="TrackBallInfoTemplate">
<Setter.Value>
<DataTemplate >
<TextBlock Text="{Binding Source.Label, ElementName=chartProvider, diag:PresentationTraceSources.TraceLevel=High}"/>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="HorizontalAxis">
<Setter.Value>
<telerik:LinearAxis x:Name="xAxis" ShowLabels="{Binding Path=Object.ShowXLabels}"
MajorStep="5"
SmartLabelsMode="SmartStep"
Minimum="{Binding Path=Object.NumMin}"
Maximum="{Binding Path=Object.NumMax}">
<telerik:LinearAxis.MajorTickTemplate >
<MultiBinding Converter="{StaticResource tickMarkConverter}">
<Binding Path="Object.ShowXTicks"/>
<Binding Source="{StaticResource visibleTicks}"/>
<Binding Source="{StaticResource hiddenTicks}"/>
</MultiBinding>
</telerik:LinearAxis.MajorTickTemplate>
</telerik:LinearAxis>
</Setter.Value>
</Setter>
</Style>
</telerik:ScatterSeriesDescriptor.Style>
</telerik:ScatterSeriesDescriptor>
</converters:CustomSeriesDescriptorSelector.LineXYDescriptor>
<converters:CustomSeriesDescriptorSelector.ScatterXYDescriptor>
<telerik:ScatterSeriesDescriptor XValuePath="X" YValuePath="Y" ItemsSourcePath="NumericData">
<telerik:ScatterSeriesDescriptor.Style>
<Style TargetType="telerik:ScatterPointSeries">
<Setter Property="DefaultVisualStyle">
<Setter.Value>
<MultiBinding Converter="{StaticResource scatterPointDefaultStyleConverter}">
<Binding Path="Symbol"/>
<Binding Path="Color"/>
</MultiBinding>
</Setter.Value>
</Setter>
<Setter Property="LegendSettings">
<Setter.Value>
<telerik:SeriesLegendSettings Title="{Binding Label}" />
</Setter.Value>
</Setter>
<Setter Property="RenderOptions">
<Setter.Value>
<telerik:Direct2DRenderOptions DefaultVisualsRenderMode="Batch"/>
</Setter.Value>
</Setter>
<Setter Property="HorizontalAxis">
<Setter.Value>
<telerik:LinearAxis x:Name="xAxis" ShowLabels="{Binding Path=Object.ShowXLabels}"
MajorStep="5"
SmartLabelsMode="SmartStep"
Minimum="{Binding Path=Object.NumMin}"
Maximum="{Binding Path=Object.NumMax}">
<telerik:LinearAxis.MajorTickTemplate >
<MultiBinding Converter="{StaticResource tickMarkConverter}">
<Binding Path="Object.ShowXTicks"/>
<Binding Source="{StaticResource visibleTicks}"/>
<Binding Source="{StaticResource hiddenTicks}"/>
</MultiBinding>
</telerik:LinearAxis.MajorTickTemplate>
</telerik:LinearAxis>
</Setter.Value>
</Setter>
</Style>
</telerik:ScatterSeriesDescriptor.Style>
</telerik:ScatterSeriesDescriptor>
</converters:CustomSeriesDescriptorSelector.ScatterXYDescriptor>
</converters:CustomSeriesDescriptorSelector>
</telerik:ChartSeriesProvider.SeriesDescriptorSelector>
</telerik:ChartSeriesProvider>
</telerik:RadCartesianChart.SeriesProvider>
</telerik:RadCartesianChart>
</Grid>
</Border>
</ControlTemplate>
<!--Style definitions-->
<!--Styles the axes of the chart-->
<Style TargetType="telerik:LinearAxis">
<Setter Property="FontSize" Value="{Binding Path=Object.Font.Size}" />
<Setter Property="LineStroke" Value="{Binding Path=Object.Font.Color, Converter={StaticResource lineStrokeSelector}}" />
<Setter Property="LabelStyle">
<Setter.Value>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="{Binding Path=Object.Font.Size}"/>
<Setter Property="Foreground" Value="{Binding Path=Object.Font.Color, Converter={StaticResource lineStrokeSelector}}"/>
<Setter Property="FontFamily" Value="{Binding Path=Object.Font.FontFamily}"/>
<Setter Property="FontWeight" Value="{Binding Path=Object.Font.Weight, Converter={StaticResource fontWeightConverter}}"/>
<Setter Property="TextDecorations" Value="{Binding Path=Object.Font.Decoration, Converter={StaticResource decorationConverter}}"/>
<Setter Property="FontStyle" Value="{Binding Path=Object.Font.Style, Converter={StaticResource fontStyleConverter}}"/>
</Style>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="telerik:DateTimeContinuousAxis">
<Setter Property="FontSize" Value="{Binding Path=Object.Font.Size}" />
<Setter Property="LineStroke" Value="{Binding Path=Object.Font.Color, Converter={StaticResource lineStrokeSelector}}" />
<Setter Property="LabelStyle">
<Setter.Value>
<Style TargetType="TextBlock">
<Setter Property="FontSize" Value="{Binding Path=Object.Font.Size}"/>
<Setter Property="Foreground" Value="{Binding Path=Object.Font.Color, Converter={StaticResource lineStrokeSelector}}"/>
<Setter Property="FontFamily" Value="{Binding Path=Object.Font.FontFamily}"/>
<Setter Property="FontWeight" Value="{Binding Path=Object.Font.Weight, Converter={StaticResource fontWeightConverter}}"/>
<Setter Property="TextDecorations" Value="{Binding Path=Object.Font.Decoration, Converter={StaticResource decorationConverter}}"/>
<Setter Property="FontStyle" Value="{Binding Path=Object.Font.Style, Converter={StaticResource fontStyleConverter}}"/>
</Style>
</Setter.Value>
</Setter>
</Style>
<!--Define the style for the DSChartControl-->
<Style TargetType="{x:Type src:DSChartControl}" x:Key="DSChartControlStyle">
<Setter Property="Control.Template" Value="{StaticResource chartTemplate}"/>
</Style>
</ResourceDictionary>
And event in the code behind
private void DateTimeContinuouseAxis_ActualVisibleRangeChanged(object sender, Telerik.Charting.DateTimeRangeChangedEventArgs e)
{
foreach (var axis in ((DSChartObject)((DSChartControl)(sender as DateTimeContinuousAxis).DataContext).Object).YAxes)
{
axis.UpdateVisibleData(e.NewRange.Minimum, e.NewRange.Maximum);
}
}
Thanks!
My event wont fire... not sure What I am missing I followed your example
I am binding to a series provider Instead of a viewmodel if that makes a difference?
<telerik:ChartSeriesProvider
Source="{Binding Object.Data}">
<telerik:ChartSeriesProvider.SeriesDescriptors>
<telerik:CategoricalSeriesDescriptor ItemsSourcePath="DataPoints"
CategoryPath="Time"
ValuePath="PointValue"
TypePath="SeriesType">
<!--Handles setting the legend information based on the data series in the
code behind-->
<!--<telerik:ScatterSeriesDescriptor.Style>
<Style TargetType="telerik:CartesianSeries">
<Setter Property="src:ChartUtilities.SeriesLegendSettings"
Value="{Binding LegendTitle, Converter={StaticResource
returnConverter}}" />
</Style>
</telerik:ScatterSeriesDescriptor.Style>-->
</telerik:CategoricalSeriesDescriptor>
</telerik:ChartSeriesProvider.SeriesDescriptors>
Update: The problem seems to be I need to switch between LinearAxis and DateTimeContinous Axes so I have several series providers that switch depending on which type of axes I need.
The scroll bar is part of the main axes of the chart not the series provider axes under behaviors. I do not see a way on how to make a setter for behaviors.
If I set the ActualVisibleRangeChanged event on the series providers it does not fire.. I verified this by modifying your example to do this. Is there a way to register this event elsewhere?
You can see my series providers defined in the code in the previous post. Thanks so much!
Hi Maxwell,
The Pan and Zoom functionality will be applied only on the main axis of the RadCartesianChart. Panning and Zooming an additional axis is not supported by the control. That is why the ActualVisibleRangeChanged event is not called.
However, there is a feature request for implementing it. Also, there is an IndividualAxisZooming SDK example that shows how to achieve individual axis zooming using some custom code. I have double-checked and in the mentioned example the ActualVisibleRangeChanged is called on both axis. I hope that helps.
Regards,
Dinko
Progress Telerik