Your Privacy Matters: We use our own and third-party cookies to improve your experience on our website. By continuing to use the website we understand that you accept their use. Cookie Policy
390
Custom series never drawn
posted

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; }
    }