Click here to Skip to main content
15,895,746 members
Articles / Desktop Programming / WPF

A WPF Graph Control Library

Rate me:
Please Sign up or sign in to vote.
4.44/5 (37 votes)
24 Apr 2008CPOL8 min read 295.5K   10.4K   96  
An article presenting a WPF library for producing extensible runtime customisable graphs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using DNBSoft.Generics;

//------------------------------------------------------------------------------//
//                                                                              //
// Author:  Derek Bartram                                                       //
// Date:    23/01/2008                                                          //
// Version: 1.000                                                               //
// Website: http://www.derek-bartram.co.uk                                      //
// Email:   webmaster@derek-bartram.co.uk                                       //
//                                                                              //
// This code is provided on a free to use and/or modify basis for personal work //
// provided that this banner remains in each of the source code files that is   //
// found in the original source. For any publicically available work (source    //
// and/or binaries 'Derek Bartram' and 'http://www.derek-bartram.co.uk' must be //
// credited in both the user documentation, source code (where applicable), and //
// in the user interface (typically Help > About would be appropiate). Please   //
// also contact myself via the provided email address to let me know where and  //
// what my code is being used for; this helps me provide better solutions for   //
// all.                                                                         //
//                                                                              //
// THIS SOURCE AND/OR COMPILED LIBRARY MUST NOT BE USED FOR COMMERCIAL WORK,    //
// including not-for-profit work, without prior consent.                        //
//                                                                              //
// This agreement overrides any other agreements made by any other parties. By  //
// using, viewing, linking, or compiling the included source or binaries you    //
// agree to the terms and conditions as set out here and in any included (if    //
// applicable) license.txt. For commercial licensing please see the web address //
// above or contact myself via email. Thank you.                                //
//                                                                              //
// Please contact me at the above email for further help, information,          //
// comments, suggestions, licensing, or feature requests. Thank you.            //
//                                                                              //
//                                                                              //
//------------------------------------------------------------------------------//

namespace DNBSoft.WPF.WPFGraph
{
    public abstract class WPFGraphPointRenderers
    {
        public class RoundPoint : BasePoint, IWPFGraphPointRenderer
        {
            #region IWPFGraphPointRenderer Members

            public void render(WPFRenderParameters parameters, WPFGraphDataPoint p)
            {
                Ellipse e = new Ellipse();
                e.Width = this.PointSize;
                e.Height = this.PointSize;
                e.Stroke = this.PointBrush;
                e.Fill = this.PointBrush;
                e.SetValue(Canvas.ZIndexProperty, 10);
                e.SetValue(Canvas.LeftProperty, parameters.transpose(WPFGraphEnumerations.Axis.X, p.X) - (this.PointSize / 2.0));
                e.SetValue(Canvas.TopProperty, parameters.transpose(WPFGraphEnumerations.Axis.Y, p.Y) - (this.PointSize / 2.0));
                parameters.Canvas.Children.Add(e);
            }

            public new void setValue(string parameter, object value)
            {
                base.setValue(parameter, value);
            }

            public new object getValue(string parameter)
            {
                return base.getValue(parameter);
            }

            public new List<WPFGraphConfigurationParameter> getConfigurationParameters()
            {
                return base.getConfigurationParameters();
            }

            #endregion
        }
        public class SqaurePoint : BasePoint, IWPFGraphPointRenderer
        {
            #region IWPFGraphPointRenderer Members

            public void render(WPFRenderParameters parameters, WPFGraphDataPoint p)
            {
                Rectangle e = new Rectangle();
                e.Width = this.PointSize;
                e.Height = this.PointSize;
                e.Stroke = this.PointBrush;
                e.Fill = this.PointBrush;
                e.SetValue(Canvas.ZIndexProperty, 10);
                e.SetValue(Canvas.LeftProperty, parameters.transpose(WPFGraphEnumerations.Axis.X, p.X) - (this.PointSize / 2.0));
                e.SetValue(Canvas.TopProperty, parameters.transpose(WPFGraphEnumerations.Axis.Y, p.Y) - (this.PointSize / 2.0));
                parameters.Canvas.Children.Add(e);
            }

            public new void setValue(string parameter, object value)
            {
                base.setValue(parameter, value);
            }

            public new object getValue(string parameter)
            {
                return base.getValue(parameter);
            }

            public new List<WPFGraphConfigurationParameter> getConfigurationParameters()
            {
                return base.getConfigurationParameters();
            }

            #endregion
        }

        public class ShadowRoundPoint : BasePoint, IWPFGraphPointRenderer
        {
            private double offsetX = 3.0;
            private double offsetY = 3.0;
            private Brush shadowBrush = new SolidColorBrush(Color.FromRgb(128, 128, 128));

            public double ShadowOffsetX
            {
                get
                {
                    return offsetX;
                }
                set
                {
                    if (offsetX != value)
                    {
                        double oldValue = offsetX;
                        offsetX = value;
                        fireEvent("ShadowOffsetX", oldValue, value);
                    }
                }
            }

            public double ShadowOffsetY
            {
                get
                {
                    return offsetY;
                }
                set
                {
                    if (offsetY != value)
                    {
                        double oldValue = offsetY;
                        offsetY = value;
                        fireEvent("ShadowOffsetY", oldValue, value);
                    }
                }
            }

            public Brush ShadowBrush
            {
                get
                {
                    return shadowBrush;
                }
                set
                {
                    if (shadowBrush != value)
                    {
                        Brush oldValue = shadowBrush;
                        shadowBrush = value;
                        fireEvent("ShadowBrush", oldValue, value);
                    }
                }
            }

            #region IWPFGraphPointRenderer Members

            public void render(WPFRenderParameters parameters, WPFGraphDataPoint p)
            {
                #region point
                Ellipse e = new Ellipse();
                e.Width = this.PointSize;
                e.Height = this.PointSize;
                e.Stroke = this.PointBrush;
                e.Fill = this.PointBrush;
                e.SetValue(Canvas.ZIndexProperty, 10);
                e.SetValue(Canvas.LeftProperty, parameters.transpose(WPFGraphEnumerations.Axis.X, p.X) - (this.PointSize / 2.0));
                e.SetValue(Canvas.TopProperty, parameters.transpose(WPFGraphEnumerations.Axis.Y, p.Y) - (this.PointSize / 2.0));
                parameters.Canvas.Children.Add(e);
                #endregion

                #region shadow
                e = new Ellipse();
                e.Width = this.PointSize;
                e.Height = this.PointSize;
                e.Stroke = this.ShadowBrush;
                e.Fill = this.ShadowBrush;
                e.SetValue(Canvas.ZIndexProperty, 1);
                e.SetValue(Canvas.LeftProperty, parameters.transpose(WPFGraphEnumerations.Axis.X, p.X) - (this.PointSize / 2.0) + offsetX);
                e.SetValue(Canvas.TopProperty, parameters.transpose(WPFGraphEnumerations.Axis.Y, p.Y) - (this.PointSize / 2.0) + offsetY);
                parameters.Canvas.Children.Add(e);
                #endregion
            }

            public new void setValue(string parameter, object value)
            {
                if (parameter.Equals("ShadowOffsetX"))
                {
                    try
                    {
                        this.ShadowOffsetX = double.Parse(value.ToString());
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else if (parameter.Equals("ShadowOffsetY"))
                {
                    try
                    {
                        this.ShadowOffsetY = double.Parse(value.ToString());
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else if (parameter.Equals("ShadowBrush"))
                {
                    try
                    {
                        this.ShadowBrush = (Brush)value;
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else
                {
                    base.setValue(parameter, value);
                }
            }

            public object getValue(string parameter)
            {
                if (parameter.Equals("ShadowOffsetX"))
                {
                    return this.ShadowOffsetX;
                }
                else if (parameter.Equals("ShadowOffsetY"))
                {
                    return this.ShadowOffsetY;
                }
                else if (parameter.Equals("ShadowBrush"))
                {
                    return shadowBrush;
                }
                else
                {
                    return base.getValue(parameter);
                }
            }

            public new List<WPFGraphConfigurationParameter> getConfigurationParameters()
            {
                List<WPFGraphConfigurationParameter> l = base.getConfigurationParameters();
                l.Add(new WPFGraphConfigurationParameter("ShadowOffsetX", (0.0).GetType()));
                l.Add(new WPFGraphConfigurationParameter("ShadowOffsetY", (0.0).GetType()));
                l.Add(new WPFGraphConfigurationParameter("ShadowBrush", shadowBrush.GetType()));
                return l;
            }

            #endregion
        }

        public class ShadowSquarePoint : BasePoint, IWPFGraphPointRenderer
        {
            private double offsetX = 3.0;
            private double offsetY = 3.0;
            private Brush shadowBrush = new SolidColorBrush(Color.FromRgb(128, 128, 128));

            public double ShadowOffsetX
            {
                get
                {
                    return offsetX;
                }
                set
                {
                    if (offsetX != value)
                    {
                        double oldValue = offsetX;
                        offsetX = value;
                        fireEvent("ShadowOffsetX", oldValue, value);
                    }
                }
            }

            public double ShadowOffsetY
            {
                get
                {
                    return offsetY;
                }
                set
                {
                    if (offsetY != value)
                    {
                        double oldValue = offsetY;
                        offsetY = value;
                        fireEvent("ShadowOffsetY", oldValue, value);
                    }
                }
            }

            public Brush ShadowBrush
            {
                get
                {
                    return shadowBrush;
                }
                set
                {
                    if (shadowBrush != value)
                    {
                        Brush oldValue = shadowBrush;
                        shadowBrush = value;
                        fireEvent("ShadowBrush", oldValue, value);
                    }
                }
            }

            #region IWPFGraphPointRenderer Members

            public void render(WPFRenderParameters parameters, WPFGraphDataPoint p)
            {
                #region point
                Rectangle e = new Rectangle();
                e.Width = this.PointSize;
                e.Height = this.PointSize;
                e.Stroke = this.PointBrush;
                e.Fill = this.PointBrush;
                e.SetValue(Canvas.ZIndexProperty, 10);
                e.SetValue(Canvas.LeftProperty, parameters.transpose(WPFGraphEnumerations.Axis.X, p.X) - (this.PointSize / 2.0));
                e.SetValue(Canvas.TopProperty, parameters.transpose(WPFGraphEnumerations.Axis.Y, p.Y) - (this.PointSize / 2.0));
                parameters.Canvas.Children.Add(e);
                #endregion

                #region shadow
                e = new Rectangle();
                e.Width = this.PointSize;
                e.Height = this.PointSize;
                e.Stroke = this.ShadowBrush;
                e.Fill = this.ShadowBrush;
                e.SetValue(Canvas.ZIndexProperty, 1);
                e.SetValue(Canvas.LeftProperty, parameters.transpose(WPFGraphEnumerations.Axis.X, p.X) - (this.PointSize / 2.0) + offsetX);
                e.SetValue(Canvas.TopProperty, parameters.transpose(WPFGraphEnumerations.Axis.Y, p.Y) - (this.PointSize / 2.0) + offsetY);
                parameters.Canvas.Children.Add(e);
                #endregion
            }

            public new void setValue(string parameter, object value)
            {
                if (parameter.Equals("ShadowOffsetX"))
                {
                    try
                    {
                        this.ShadowOffsetX = double.Parse(value.ToString());
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else if (parameter.Equals("ShadowOffsetY"))
                {
                    try
                    {
                        this.ShadowOffsetY = double.Parse(value.ToString());
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else if (parameter.Equals("ShadowBrush"))
                {
                    try
                    {
                        this.ShadowBrush = (Brush)value;
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else
                {
                    base.setValue(parameter, value);
                }
            }

            public object getValue(string parameter)
            {
                if (parameter.Equals("ShadowOffsetX"))
                {
                    return this.ShadowOffsetX;
                }
                else if (parameter.Equals("ShadowOffsetY"))
                {
                    return this.ShadowOffsetY;
                }
                else if (parameter.Equals("ShadowBrush"))
                {
                    return shadowBrush;
                }
                else
                {
                    return base.getValue(parameter);
                }
            }

            public new List<WPFGraphConfigurationParameter> getConfigurationParameters()
            {
                List<WPFGraphConfigurationParameter> l = base.getConfigurationParameters();
                l.Add(new WPFGraphConfigurationParameter("ShadowOffsetX", (0.0).GetType()));
                l.Add(new WPFGraphConfigurationParameter("ShadowOffsetY", (0.0).GetType()));
                l.Add(new WPFGraphConfigurationParameter("ShadowBrush", shadowBrush.GetType()));
                return l;
            }

            #endregion
        }

        public abstract class BasePoint
        {
            public double size = 3;
            public Brush brush = new SolidColorBrush(Color.FromRgb(0, 0, 255));
            public event WPFGraphDelegates.RendererChangedEventDelegate RendererChanged;

            public double PointSize
            {
                get
                {
                    return size;
                }
                set
                {
                    if (size != value)
                    {
                        double oldValue = size;
                        size = value;
                        fireEvent("LineThickness", oldValue, value);
                    }
                }
            }

            public Brush PointBrush
            {
                get
                {
                    return brush;
                }
                set
                {
                    if (brush != value)
                    {
                        Brush oldValue = brush;
                        brush = value;
                        fireEvent("PointBrush", oldValue, value);
                    }
                }
            }

            protected void fireEvent(String property, object oldValue, object newValue)
            {
                if (RendererChanged != null)
                {
                    RendererChanged(this,
                        new WPFGraphEventClasses.RendererChangedEventArgs(property, oldValue, newValue));
                }
            }

            public void setValue(string parameter, object value)
            {
                if (parameter.Equals("PointSize"))
                {
                    try
                    {
                        this.PointSize = double.Parse(value.ToString());
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else if (parameter.Equals("PointBrush"))
                {
                    try
                    {
                        this.PointBrush = (Brush)value;
                    }
                    catch (Exception)
                    {
                        throw new WPFGraphExceptions.ParameterFormatException();
                    }
                }
                else
                {
                    throw new WPFGraphExceptions.PropertyNotFoundException();
                }
            }

            public object getValue(String parameter)
            {
                if (parameter.Equals("PointSize"))
                {
                    return this.PointSize;
                }
                else if (parameter.Equals("PointBrush"))
                {
                    return this.PointBrush;
                }
                else
                {
                    throw new WPFGraphExceptions.PropertyNotFoundException();
                }
            }

            public List<WPFGraphConfigurationParameter> getConfigurationParameters()
            {
                List<WPFGraphConfigurationParameter> l = new List<WPFGraphConfigurationParameter>();
                l.Add(new WPFGraphConfigurationParameter("PointSize", (0.0).GetType()));
                l.Add(new WPFGraphConfigurationParameter("PointBrush", PointBrush.GetType()));
                return l;
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Rail Research UK
United Kingdom United Kingdom
I originally studied for a masters in engineering of software engineering at The University of Birmingham during 2000-2004, of which I received a 2:1. I continued at Birmingham University working with Civil Engineering and Rail Research UK where I am currently in my final year of a 3 year PhD project developing a Computational Intelligent Approach to Railway Intervention Planning. Although my work has a significant focus on railway engineering and associated practices much of my work is with data mining (on SQL Server 2008) and computational intelligence (CI) techniques. My key areas of expertise in CI are clustering algorithms (including Rival Penalised Competitive Learning) and evolutionary algorithms.

Outside of my formal work I enjoy testing the latest technologies such as .NET 3.5 and the many frameworks of which it comprises (mainly WPF). I have several projects on the go including a .NET and DirectX port of Quake 3 and many utility libraries. I also maintain an extensive website coded in Cold Fusion which is regularly updated; more information is available about me there.

Comments and Discussions