Hello! I am trying to create a custom series to display lines and ranges over an existing XamDataChart, but am having some problems.Using your "Creating Custom Series" code as a start, I tried to start with a simple case: a series with the functionality of your ValueOverlay class, that draws a single line at a particular value on the YAxis.However, when I try to add the series to my chart, it never gets drawn (the Viewport is Empty and the RootCanvas is null in the RenderSeriesOverride method). Can you see what I'm doing wrong?Thanks for any help you can provide.Best,Ed
============
class LineSeries : Series { public const string XAxisPropertyName = "XAxis"; public const string YAxisPropertyName = "YAxis"; public const string ValuePropertyName = "Value"; /// <summary> /// The value of the line to draw /// </summary> public static readonly DependencyProperty ValueProperty = DependencyProperty.Register( ValuePropertyName, typeof(double), typeof(LineSeries), new PropertyMetadata(0D)); public double Value { get { return (double)this.GetValue(ValueProperty); } set { this.SetValue(ValueProperty, value); RaisePropertyChanged(ValuePropertyName, 0, value); } } public static readonly DependencyProperty XAxisProperty = DependencyProperty.Register( XAxisPropertyName, typeof(NumericXAxis), typeof(LineSeries), new PropertyMetadata(null, (sender, e) => { LineSeries series = (LineSeries)sender; series.RaisePropertyChanged(XAxisPropertyName, e.OldValue, e.NewValue); } ) ); public NumericXAxis XAxis { get { return this.GetValue(XAxisProperty) as NumericXAxis; } set { this.SetValue(XAxisProperty, value); } } public static readonly DependencyProperty YAxisProperty = DependencyProperty.Register( YAxisPropertyName, typeof(NumericYAxis), typeof(LineSeries), new PropertyMetadata(null, (sender, e) => { LineSeries series = (LineSeries)sender; series.RaisePropertyChanged(YAxisPropertyName, e.OldValue, e.NewValue); } ) ); public NumericYAxis YAxis { get { return this.GetValue(YAxisProperty) as NumericYAxis; } set { this.SetValue(YAxisProperty, value); } } /// <summary> /// Calls rendering of this series any time the Viewport rect has changed. /// </summary> /// <param name="oldViewportRect"></param> /// <param name="newViewportRect"></param> protected override void ViewportRectChangedOverride(Rect oldViewportRect, Rect newViewportRect) { base.ViewportRectChangedOverride(oldViewportRect, newViewportRect); this.RenderSeries(false); } /// <summary> /// Calls rendering of this series any time the Window rect has changed. /// </summary> /// <param name="oldWindowRect"></param> /// <param name="newWindowRect"></param> protected override void WindowRectChangedOverride(Rect oldWindowRect, Rect newWindowRect) { base.WindowRectChangedOverride(oldWindowRect, newWindowRect); this.RenderSeries(false); } /// <summary> /// Checks if series should be redrawn any time a property of the series has changed /// </summary> /// <param name="sender"></param> /// <param name="propertyName"></param> /// <param name="oldValue"></param> /// <param name="newValue"></param> protected override void PropertyUpdatedOverride(object sender, string propertyName, object oldValue, object newValue) { base.PropertyUpdatedOverride(sender, propertyName, oldValue, newValue); Console.WriteLine(propertyName); switch (propertyName) { //renders series on changes made to the ranges case ValuePropertyName: this.RenderSeries(false); if (this.XAxis != null) { this.XAxis.UpdateRange(); } if (this.YAxis != null) { this.YAxis.UpdateRange(); } break; //renders seris if a new X-axis is assigned case XAxisPropertyName: if (oldValue != null) { ((Axis)oldValue).DeregisterSeries(this); } if (newValue != null) { ((Axis)newValue).RegisterSeries(this); } if ((XAxis != null && !XAxis.UpdateRange()) || (newValue == null && oldValue != null)) { RenderSeries(false); } break; //renders series if a new Y-axis is assigned case YAxisPropertyName: if (oldValue != null) { ((Axis)oldValue).DeregisterSeries(this); } if (newValue != null) { ((Axis)newValue).RegisterSeries(this); } if ((YAxis != null && !YAxis.UpdateRange()) || (newValue == null && oldValue != null)) { RenderSeries(false); } break; } } /// <summary> /// Calculates range of a given axis based on the X/Y values of the data items /// </summary> /// <param name="axis"></param> /// <returns></returns> protected override AxisRange GetRange(Axis axis) { //Set the minimum range for the Axis to include the point where the line is drawn if (axis == this.YAxis) { return new AxisRange(this.Value, this.Value); } else { //Since there is no axis range needed to display this series, return null. return null; } } protected override void RenderSeriesOverride(bool animate) { //disable series rendering with transitions (Motion Framework) base.RenderSeriesOverride(animate); //check to see if the series can be rendered if (this.Viewport.IsEmpty || this.RootCanvas == null || this.XAxis == null || this.YAxis == null ) { return; } //clear the RootCanvas on every render of the series this.RootCanvas.Children.Clear(); Grid grid = new Grid(); double x1 = this.Viewport.Left; double x2 = this.Viewport.Right; double y1 = this.YAxis.GetScaledValue(this.Value, this.SeriesViewer.WindowRect, this.Viewport); double y2 = y1; Line line = new Line(); line.StrokeThickness = 4; line.Stroke = Brushes.Red; line.X1 = x1; line.Y1 = y1; line.X2 = x2; line.Y2 = y2; grid.Children.Add(line); Canvas.SetZIndex(grid, 0); this.RootCanvas.Children.Add(grid); } }
=================
<Window x:Class="WpfApplication2.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ig="http://schemas.infragistics.com/xaml" xmlns:igWPF="http://schemas.infragistics.com/xaml/wpf" xmlns:local="clr-namespace:WpfApplication2" Title="MainWindow" Height="350" Width="525" > <Grid> <Canvas> <ig:XamDock RenderTransformOrigin="0.467,0.444" Height="156" Width="280" Canvas.Left="157" Canvas.Top="112"> <Label Content="{Binding Path=YAxisTitle}" Margin="0,0,0,0" ig:XamDock.Edge="OutsideLeft" ig:XamDock.VerticalDockAlignment="Center"> <Label.LayoutTransform> <RotateTransform Angle="-90"/> </Label.LayoutTransform> </Label> <Label Content="{Binding Path=XAxisTitle}" Margin="0,0,0,0" ig:XamDock.Edge="OutsideBottom" ig:XamDock.HorizontalDockAlignment="Center"/> <Label Content="{Binding Path=GraphTitle}" Margin="0,0,0,0" ig:XamDock.Edge="OutsideTop" ig:XamDock.HorizontalDockAlignment="Center"/> <ig:XamDataChart Background="White" Margin="-128,-89,-52,-36" x:Name="Chart" > <ig:XamDataChart.DataContext> <local:SimpleDataCollection /> </ig:XamDataChart.DataContext> <ig:XamDataChart.Axes> <ig:NumericXAxis x:Name="XAxis"> <ig:NumericXAxis.LabelSettings > <ig:AxisLabelSettings Location="OutsideBottom" /> </ig:NumericXAxis.LabelSettings> </ig:NumericXAxis> <ig:NumericYAxis x:Name="YAxis"> <ig:NumericYAxis.LabelSettings > <ig:AxisLabelSettings Location="OutsideLeft" /> </ig:NumericYAxis.LabelSettings> </ig:NumericYAxis> </ig:XamDataChart.Axes> <ig:XamDataChart.Series> <ig:ScatterLineSeries x:Name="data" XMemberPath="X" YMemberPath="Y" ItemsSource="{Binding}" XAxis="{Binding ElementName=XAxis}" YAxis="{Binding ElementName=YAxis}" /> <local:LineSeries x:Name="range" Value = "4.5" XAxis="{Binding ElementName=XAxis}" YAxis="{Binding ElementName=YAxis}"/> </ig:XamDataChart.Series> </ig:XamDataChart> </ig:XamDock> </Canvas> </Grid>
======================
public class SimpleDataCollection : ObservableCollection<SimpleDataPoint> { public SimpleDataCollection() { this.Add(new SimpleDataPoint() { X = 1.0, Y = 3.0 }); this.Add(new SimpleDataPoint() { X = 2.0, Y = 2.0 }); this.Add(new SimpleDataPoint() { X = 3.0, Y = 3.0 }); this.Add(new SimpleDataPoint() { X = 4.0, Y = 4.0 }); this.Add(new SimpleDataPoint() { X = 5.0, Y = 5.0 }); this.Add(new SimpleDataPoint() { X = 6.0, Y = 6.0 }); this.Add(new SimpleDataPoint() { X = 7.0, Y = 5.0 }); } } /// <summary> /// Simple storage class for pair of double values /// </summary> public class SimpleDataPoint { public double X { get; set; } public double Y { get; set; } }
Hello Ed,
Thank you for your feedback. I am glad that you resolved your issue and I believe that other community members may benefit from this as well.
Thanks again.
It works perfectly! Thanks very much for your help!
Hello,
I have created a sample project using your code, but I added Style for the custom Series. I added the Style in the App.xaml file. Basically I set its ControlTemplate Property, where I put the “RootCanvas” Canvas element. These are the first two steps in the following tutorial:
http://help.infragistics.com/Help/NetAdvantage/WPF/2012.2/CLR4.0/html/xamDataChart_Creating_Custom_Series.html
Please let me know if this helps you or you need further assistance on this matter.
Looking forward for your reply.
Sorry,forgot to say this is using WPF.
Thank you for your post. Could you tell us whether you use WPF or Silverlight.