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

How to create stock charts using the Silverlight Toolkit

Rate me:
Please Sign up or sign in to vote.
4.70/5 (15 votes)
16 Feb 2009CPOL2 min read 142.3K   2.7K   65  
An article on how to create a Candlestick stock chart using the Silverlight Toolkit.
// (c) Copyright Microsoft Corporation.
// This source is subject to the Microsoft Public License (Ms-PL).
// Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
// All other rights reserved.

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;

namespace Microsoft.Windows.Controls.DataVisualization.Charting
{
    /// <summary>
    /// A dynamic series with axes and only one legend item and style for all 
    /// data points.
    /// </summary>
    /// <QualityBand>Preview</QualityBand>
    public abstract class DataPointSingleSeriesWithAxes : DataPointSeriesWithAxes, IRequireGlobalSeriesIndex
    {
        /// <summary>
        /// Gets the single legend item associated with the series.
        /// </summary>
        protected LegendItem LegendItem
        {
            get
            {
                if (LegendItems.Count == 0)
                {
                    this.LegendItems.Add(CreateLegendItem());
                }
                return this.LegendItems[0] as LegendItem;
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether a custom title is in use.
        /// </summary>
        private bool CustomTitleInUse { get; set; }

        #region public Style DataPointStyle
        /// <summary>
        /// Gets or sets the style to use for the data points.
        /// </summary>
        public Style DataPointStyle
        {
            get { return GetValue(DataPointStyleProperty) as Style; }
            set { SetValue(DataPointStyleProperty, value); }
        }

        /// <summary>
        /// Identifies the DataPointStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty DataPointStyleProperty =
            DependencyProperty.Register(
                "DataPointStyle",
                typeof(Style),
                typeof(DataPointSingleSeriesWithAxes),
                null);

        #endregion public Style DataPointStyle

        /// <summary>
        /// Gets or sets the actual style of used for the data points.
        /// </summary>
        protected Style ActualDataPointStyle { get; set; }

        #region public int GlobalSeriesIndex
        /// <summary>
        /// Gets the index of the series in the Parent's series collection.
        /// </summary>
        public int GlobalSeriesIndex
        {
            get { return (int)GetValue(GlobalSeriesIndexProperty); }
            private set { SetValue(GlobalSeriesIndexProperty, value); }
        }

        /// <summary>
        /// Identifies the GlobalSeriesIndex dependency property.
        /// </summary>
        public static readonly DependencyProperty GlobalSeriesIndexProperty =
            DependencyProperty.Register(
                "GlobalSeriesIndex",
                typeof(int),
                typeof(Series),
                new PropertyMetadata(-1, OnGlobalSeriesIndexPropertyChanged));

        /// <summary>
        /// GlobalSeriesIndexProperty property changed handler.
        /// </summary>
        /// <param name="d">Series that changed its Index.</param>
        /// <param name="e">Event arguments.</param>
        private static void OnGlobalSeriesIndexPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            DataPointSingleSeriesWithAxes source = (DataPointSingleSeriesWithAxes)d;
            int oldValue = (int)e.OldValue;
            int newValue = (int)e.NewValue;
            source.OnGlobalSeriesIndexPropertyChanged(oldValue, newValue);
        }

        /// <summary>
        /// GlobalSeriesIndexProperty property changed handler.
        /// </summary>
        /// <param name="oldValue">Old value.</param>
        /// <param name="newValue">New value.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2233:OperationsShouldNotOverflow", MessageId = "newValue+1", Justification = "Impractical to add as many Series as it would take to overflow.")]
        protected virtual void OnGlobalSeriesIndexPropertyChanged(int oldValue, int newValue)
        {
            LegendItem.Content = Title;

            if (!CustomTitleInUse)
            {
                Title = (0 <= newValue) ? string.Format(CultureInfo.CurrentCulture, Properties.Resources.Series_OnGlobalSeriesIndexPropertyChanged_UntitledSeriesFormatString, newValue + 1) : null;
                // Setting Title will set CustomTitleInUse; reset it now
                CustomTitleInUse = false;
            }
        }
        #endregion public int GlobalSeriesIndex

        /// <summary>
        /// Called when the Title property changes.
        /// </summary>
        /// <param name="oldValue">Old value of the Title property.</param>
        /// <param name="newValue">New value of the Title property.</param>
        protected override void OnTitleChanged(object oldValue, object newValue)
        {
            // Title property is being set, so a custom Title is in use
            CustomTitleInUse = true;
            LegendItem.Content = Title;
        }

        /// <summary>
        /// Initializes a new instance of the DynamicSingleSeries class.
        /// </summary>
        internal DataPointSingleSeriesWithAxes()
        {
        }

        /// <summary>
        /// Returns the data point style to use for all data points in the 
        /// series.
        /// </summary>
        /// <returns>The data point style to use for all charts in the series.
        /// </returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This property does more work than get functions typically do.")]
        protected abstract Style GetDataPointStyleFromHost();

        /// <summary>
        /// Insert grid containing data point used for legend item into the 
        /// plot area.
        /// </summary>
        /// <param name="oldValue">The old plot area.</param>
        /// <param name="newValue">The new plot area.</param>
        protected override void OnPlotAreaChanged(Canvas oldValue, Canvas newValue)
        {
            if (newValue != null)
            {
                CreateLegendItemDataPoint();
            }
            base.OnPlotAreaChanged(oldValue, newValue);
        }

        /// <summary>
        /// When the series host property is set retrieves a style to use for all the
        /// data points.
        /// </summary>
        /// <param name="oldValue">The old series host value.</param>
        /// <param name="newValue">The new series host value.</param>
        protected override void OnSeriesHostPropertyChanged(ISeriesHost oldValue, ISeriesHost newValue)
        {
            base.OnSeriesHostPropertyChanged(oldValue, newValue);

            if (newValue != null)
            {
                ActualDataPointStyle = DataPointStyle ?? GetDataPointStyleFromHost();
                CreateLegendItemDataPoint();
            }
        }

        /// <summary>
        /// Creates the LegendItem Control if conditions are right.
        /// </summary>
        private void CreateLegendItemDataPoint()
        {
            DataPoint dataPoint = CreateDataPoint();
            dataPoint.Style = ActualDataPointStyle;
            LegendItem.Content = Title;
            LegendItem.Loaded += delegate
            {
                // Wait for Loaded to set the DataPoint
                LegendItem.DataContext = dataPoint;
            };
        }

        /// <summary>
        /// Method invoked after data points have been loaded from the ItemsSource.
        /// </summary>
        protected override void OnDataPointsLoaded()
        {
            base.OnDataPointsLoaded();

            if (null != PlotArea)
            {
                // Create the Control for use by LegendItem
                // Add it to the visual tree so that its style will be applied
                if (null != LegendItem.DataContext)
                {
                    PlotArea.Children.Remove(LegendItem.DataContext as UIElement);
                }
            }
        }

        /// <summary>
        /// Sets the style of the data point to the single style used for all
        /// data points.
        /// </summary>
        /// <param name="dataPoint">The data point to apply the style to.
        /// </param>
        /// <param name="dataContext">The object associated with the data point.
        /// </param>
        protected override void PrepareDataPoint(DataPoint dataPoint, object dataContext)
        {
            if (dataPoint.Style == null)
            {
                dataPoint.Style = ActualDataPointStyle;
            }

            base.PrepareDataPoint(dataPoint, dataContext);
        }

        /// <summary>
        /// This method updates the global series index property.
        /// </summary>
        /// <param name="globalIndex">The global index of the series.</param>
        public void GlobalSeriesIndexChanged(int globalIndex)
        {
            this.GlobalSeriesIndex = globalIndex;
        }

        /// <summary>
        /// Refreshes the styles in the series.
        /// </summary>
        public override void RefreshStyles()
        {
            if (this.SeriesHost != null)
            {
                ActualDataPointStyle = DataPointStyle ?? GetDataPointStyleFromHost();
                CreateLegendItemDataPoint();
                Refresh();
            }
        }
    }
}

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
South Africa South Africa
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions