Click here to Skip to main content
15,883,705 members
Articles / Desktop Programming / WPF

OpenWPFChart: assembling charts from components: Part I - Parts

Rate me:
Please Sign up or sign in to vote.
4.29/5 (17 votes)
19 Mar 2009CPOL14 min read 81.7K   4K   81  
Provides the component model along with base components to assemble charts.
// <copyright file="MainWindow.xaml.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008-2009 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2009-01-04</date>
// <summary>OpenWPFChart library. CurveChart Control use Sample.</summary>
// <revision>$Id: MainWindow.xaml.cs 18093 2009-03-16 04:15:06Z unknown $</revision>

using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.Linq;
using System.IO;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Media;
using Microsoft.Win32; // For OpenFileDialog and SaveFileDialog
using OpenWPFChart.Helpers;
using OpenWPFChart.Parts;

namespace CurveChartControlSample
{
	/// <summary>
	/// CurveChart Control use Sample.
	/// </summary>
	public partial class MainWindow : Window
	{
		/// <summary>
		/// Initializes a new instance of the <see cref="MainWindow"/> class.
		/// </summary>
		public MainWindow()
		{
			InitializeComponent();
		}

		/// <summary>
		/// Raises the <see cref="E:System.Windows.FrameworkElement.Initialized"/> event. 
		/// This method is invoked whenever <see cref="P:System.Windows.FrameworkElement.IsInitialized"/> 
		/// is set to true internally.
		/// </summary>
		/// <param name="e">The <see cref="T:System.Windows.RoutedEventArgs"/> 
		/// that contains the event data.</param>
		protected override void OnInitialized(EventArgs e)
		{
			base.OnInitialized(e);

			// Load MRU files list
			ArrayList mru = Properties.Settings.Default.MRU;
			if (mru != null)
			{
				// MRU entri id a string of the following format:
				// MruInfo.Hint.ToString + " " + MruInfo.FileName
				foreach (string strMruInfo in mru)
				{
					int spaceIndex = strMruInfo.IndexOf(' ');
					if (spaceIndex < 0)
						continue;

					string strHint = strMruInfo.Substring(0, spaceIndex);
					MruInfo.MruInfoHint hint = (MruInfo.MruInfoHint)Enum.Parse(typeof(MruInfo.MruInfoHint), strHint);
					string fileName = strMruInfo.Substring(spaceIndex + 1);
					MruInfo mruInfo = new MruInfo(fileName, hint);
					MenuItem item = new MenuItem() 
					{
						Header = mruInfo.ToString(),
						Tag = mruInfo
					};
					item.Click += mru_Click;
					mnuRecentFiles.Items.Add(item);
				}
			}
		}

		/// <summary>
		/// Saves the settings.
		/// Raises the <see cref="E:System.Windows.Window.Closed"/> event.
		/// </summary>
		/// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
		protected override void OnClosed(EventArgs e)
		{
			base.OnClosed(e);

			// MRU files list.
			ArrayList mru = null;
			if (mnuRecentFiles.Items.Count > 0)
			{
				mru = new ArrayList();
				foreach (MenuItem item in mnuRecentFiles.Items)
				{
					mru.Add(item.Tag.ToString());
				}
			}
			Properties.Settings.Default.MRU = mru;

			Properties.Settings.Default.Save();
		}

		/// <summary>
		/// MRU Item Information class.
		/// </summary>
		/// <remarks>
		/// Contains the <see cref="FileName"/> and <see cref="Hint"/> properties.
		/// </remarks>
		class MruInfo
		{
			/// <summary>
			/// Type of MRU Item.
			/// </summary>
			public enum MruInfoHint
			{
				/// <summary>
				/// The MRU Item is of Curve type.
				/// </summary>
				Curve,
				/// <summary>
				/// The MRU Item is of Column type.
				/// </summary>
				Column
			}

			/// <summary>
			/// Initializes a new instance of the <see cref="MruInfo"/> class.
			/// </summary>
			/// <param name="fileName">Name of the file.</param>
			/// <param name="hint">The hint.</param>
			public MruInfo(string fileName, MruInfoHint hint)
			{
				FileName = fileName;
				Hint = hint;
			}

			/// <summary>
			/// Gets or sets the name of the file.
			/// </summary>
			/// <value>The name of the file.</value>
			public string FileName { get; private set; }
			/// <summary>
			/// Gets or sets the hint.
			/// </summary>
			/// <value>The hint.</value>
			public MruInfoHint Hint { get; private set; }

			/// <inheritdocs/>
			public override string ToString()
			{
				return Hint.ToString() + " " + FileName;
			}

			/// <inheritdocs/>
			public override bool Equals(object obj)
			{
				if (obj == null || obj.GetType() != typeof(MruInfo))
					return false;
				MruInfo other = obj as MruInfo;
				return (FileName == other.FileName) && (Hint == other.Hint);
			}

			/// <inheritdocs/>
			public override int GetHashCode()
			{
				return FileName.GetHashCode() ^ Hint.GetHashCode();
			}
		}

		/// <summary>
		/// Loads Curve ItemData from the file.
		/// </summary>
		/// <param name="fileName">Name of the file.</param>
		/// <exception cref="Exception">Misc IO and file parser exceptions.</exception>
		private bool loadCurveData(string fileName)
		{
			// Parse the Data File.
			string xAxisLabel = null;
			ObservableCollection<ItemData> dataCollection = null;
			FileInfo fi = new FileInfo(fileName);
			try
			{
				if (fi.Extension.ToLower() == ".txt")
					dataCollection = SpaceSeparatedDataFileParser.Parse(fileName, out xAxisLabel);
				else if (fi.Extension.ToLower() == ".xml")
					dataCollection = XMLDataFileParser.Parse(fileName, out xAxisLabel);

				if (dataCollection == null || dataCollection.Count == 0)
					return false;
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
				return false;
			}

			// Clear Chart Data Source. It's required because otherwise we could have an exception
			// on Chart Scales setting.
			chart.ItemsSource = null;

			// Set X-Chart Scale
			if (dataCollection[0] is SampledCurveData<double, double>)
			{
				IEnumerable<DataPoint<double, double>> points = (dataCollection[0] as SampledCurveData<double, double>).Points;
				double xMin = points.First<DataPoint<double, double>>().X;
				double xMax = points.Last<DataPoint<double, double>>().X;
				chart.HorizontalScale = new ChartLinearScale(xMin, xMax
					, chart.ChartAreaRenderSize.Width > 0 ? chart.ChartAreaRenderSize.Width : ActualWidth);
			}
			else if (dataCollection[0] is SampledCurveData<DateTime, double>)
			{
				IEnumerable<DataPoint<DateTime, double>> points = (dataCollection[0] as SampledCurveData<DateTime, double>).Points;
				DateTime xMin = points.First<DataPoint<DateTime, double>>().X;
				DateTime xMax = points.Last<DataPoint<DateTime, double>>().X;
				chart.HorizontalScale = new ChartDateTimeScale(xMin, xMax
					, chart.ChartAreaRenderSize.Width > 0 ? chart.ChartAreaRenderSize.Width : ActualWidth);
			}
			else if (dataCollection[0] is SampledCurveData<object, double>)
			{
				IEnumerable<DataPoint<object, double>> points = (dataCollection[0] as SampledCurveData<object, double>).Points;
				object xMin = points.First<DataPoint<object, double>>().X;
				object xMax = points.Last<DataPoint<object, double>>().X;
				chart.HorizontalScale = new ChartSeriesScale(from pt in points select pt.X
					, xMin, xMax, chart.ChartAreaRenderSize.Width > 0 ? chart.ChartAreaRenderSize.Width : ActualWidth);
			}
			else if (dataCollection[0] is ScatteredPointsData<double, double>)
			{
				IEnumerable<DataPoint<double, double>> points = (dataCollection[0] as ScatteredPointsData<double, double>).Points;
				object xMin = points.First<DataPoint<double, double>>().X;
				object xMax = points.Last<DataPoint<double, double>>().X;
				chart.HorizontalScale = new ChartLinearScale(xMin, xMax, chart.ActualWidth > 0 ? chart.ActualWidth : ActualWidth);
			}
			else
				return false;

			// Set Y-Chart Scale
			double yMax = double.MinValue, yMin = double.MaxValue;
			for (int i = 0; i < dataCollection.Count; ++i)
			{
				IEnumerable<double> ordinates = null;
				if (dataCollection[i] is SampledCurveData<double, double>)
					ordinates = from pt in (dataCollection[i] as SampledCurveData<double, double>).Points select pt.Y;
				else if (dataCollection[i] is SampledCurveData<DateTime, double>)
					ordinates = from pt in (dataCollection[i] as SampledCurveData<DateTime, double>).Points select pt.Y;
				else if (dataCollection[0] is SampledCurveData<object, double>)
					ordinates = from pt in (dataCollection[i] as SampledCurveData<object, double>).Points select pt.Y;
				else if (dataCollection[0] is ScatteredPointsData<double, double>)
					ordinates = from pt in (dataCollection[i] as ScatteredPointsData<double, double>).Points select pt.Y;
				else
					continue;

				double min = ordinates.Min();
				if (min < yMin)
					yMin = min;
				double max = ordinates.Max();
				if (max > yMax)
					yMax = max;
			}

			// Chart VerticalScale.
			chart.VerticalScale = new ChartLinearScale(yMax, yMin
				, chart.ChartAreaRenderSize.Height > 0 ? chart.ChartAreaRenderSize.Height : ActualHeight);

			// PointMarker
			GeometryDrawing pointMarker = new GeometryDrawing(Brushes.Brown, new Pen(Brushes.Red, 1)
				, new EllipseGeometry(new Point(0, 0), 4, 4));
			pointMarker.Freeze();

			// Create DataViewCollection.
			ObservableCollection<ItemDataView> dataViewCollection = new ObservableCollection<ItemDataView>();
			for (int i = 0; i < dataCollection.Count; ++i)
			{
				if (dataCollection[i] is SampledCurveData<double, double>
					|| dataCollection[i] is SampledCurveData<DateTime, double>
					|| dataCollection[i] is SampledCurveData<object, double>)
				{
					SampledCurveDataView dataView = new SampledCurveDataView()
					{
						ItemData = dataCollection[i],
						HorizontalScale = chart.HorizontalScale,
						VerticalScale = chart.VerticalScale,
						PointMarker = pointMarker
					};

					dataViewCollection.Add(dataView);
				}
				else if (dataCollection[i] is ScatteredPointsData<double, double>)
				{
					ScatteredPointsDataView dataView = new ScatteredPointsDataView()
					{
						ItemData = dataCollection[i],
						HorizontalScale = chart.HorizontalScale,
						VerticalScale = chart.VerticalScale,
						PointMarker = pointMarker
					};

					dataViewCollection.Add(dataView);
				}
			}

			// Set Chart Data Source.
			chart.ItemsSource = dataViewCollection;
			// Set Horizontal Axis label.
			chart.HorizontalAxisTitle = xAxisLabel;

			// Reguery SwapLinLogScaleCommand
			((SwapLinLogScaleCommandImpl)SwapLinLogScaleCommand).NotifyChanged();

			return true;
		}

		/// <summary>
		/// Loads Column ItemData from the file.
		/// </summary>
		/// <param name="fileName">Name of the file.</param>
		/// <exception cref="Exception">Misc IO and file parser exceptions.</exception>
		private bool loadColumnItemData(string fileName)
		{
			// Parse the Data File.
			string xAxisLabel = null;
			ObservableCollection<ItemData> dataCollection = null;
			FileInfo fi = new FileInfo(fileName);
			try
			{
				if (fi.Extension.ToLower() == ".txt")
					dataCollection = SpaceSeparatedDataFileParser.Parse(fileName, out xAxisLabel);
				else if (fi.Extension.ToLower() == ".xml")
					dataCollection = XMLDataFileParser.Parse(fileName, out xAxisLabel);

				if (dataCollection == null || dataCollection.Count == 0)
					return false;
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
				return false;
			}

			// Clear Chart Data Source. It's required because otherwise we could have an exception
			// on Chart Scales setting.
			chart.ItemsSource = null;

			// Set X-Chart Scale
			if (dataCollection[0] is SampledCurveData<double, double>)
			{
				IEnumerable<DataPoint<double, double>> points = (dataCollection[0] as SampledCurveData<double, double>).Points;
				double xMin = points.First<DataPoint<double, double>>().X;
				double xMax = points.Last<DataPoint<double, double>>().X;
				chart.HorizontalScale = new ChartLinearScale(xMin, xMax
					, chart.ChartAreaRenderSize.Width > 0 ? chart.ChartAreaRenderSize.Width : ActualWidth);
			}
			else if (dataCollection[0] is SampledCurveData<DateTime, double>)
			{
				IEnumerable<DataPoint<DateTime, double>> points = (dataCollection[0] as SampledCurveData<DateTime, double>).Points;
				DateTime xMin = points.First<DataPoint<DateTime, double>>().X;
				DateTime xMax = points.Last<DataPoint<DateTime, double>>().X;
				chart.HorizontalScale = new ChartDateTimeScale(xMin, xMax
					, chart.ChartAreaRenderSize.Width > 0 ? chart.ChartAreaRenderSize.Width : ActualWidth);
			}
			else if (dataCollection[0] is SampledCurveData<object, double>)
			{
				IEnumerable<DataPoint<object, double>> points = (dataCollection[0] as SampledCurveData<object, double>).Points;
				object xMin = points.First<DataPoint<object, double>>().X;
				object xMax = points.Last<DataPoint<object, double>>().X;
				chart.HorizontalScale = new ChartSeriesScale(from pt in points select pt.X
					, xMin, xMax, chart.ChartAreaRenderSize.Width > 0 ? chart.ChartAreaRenderSize.Width : ActualWidth);
			}
			else
				return false;

			// Set Y-Chart Scale
			double yMax = double.MinValue, yMin = double.MaxValue;
			for (int i = 0; i < dataCollection.Count; ++i)
			{
				IEnumerable<double> ordinates = null;
				if (dataCollection[i] is SampledCurveData<double, double>)
					ordinates = from pt in (dataCollection[i] as SampledCurveData<double, double>).Points select pt.Y;
				else if (dataCollection[i] is SampledCurveData<DateTime, double>)
					ordinates = from pt in (dataCollection[i] as SampledCurveData<DateTime, double>).Points select pt.Y;
				else if (dataCollection[0] is SampledCurveData<object, double>)
					ordinates = from pt in (dataCollection[i] as SampledCurveData<object, double>).Points select pt.Y;
				else
					continue;

				double min = ordinates.Min();
				if (min < yMin)
					yMin = min;
				double max = ordinates.Max();
				if (max > yMax)
					yMax = max;
			}

			// Chart VerticalScale.
			chart.VerticalScale = new ChartLinearScale(yMax, yMin
				, chart.ChartAreaRenderSize.Height > 0 ? chart.ChartAreaRenderSize.Height : ActualHeight);

			// PointMarker
			GeometryDrawing pointMarker = new GeometryDrawing(Brushes.Brown, new Pen(Brushes.Red, 1)
				, new EllipseGeometry(new Point(0, 0), 4, 4));
			pointMarker.Freeze();

			// Create DataViewCollection.
			ObservableCollection<ItemDataView> dataViewCollection = new ObservableCollection<ItemDataView>();
			for (int i = 0; i < dataCollection.Count; ++i)
			{
				if (dataCollection[i] is SampledCurveData<double, double>
					|| dataCollection[i] is SampledCurveData<DateTime, double>
					|| dataCollection[i] is SampledCurveData<object, double>)
				{
					ColumnChartItemDataView dataView = new ColumnChartItemDataView()
					{
						ItemData = dataCollection[i],
						HorizontalScale = chart.HorizontalScale,
						VerticalScale = chart.VerticalScale,
						PointMarker = pointMarker
					};

					dataViewCollection.Add(dataView);
				}
			}

			// Set Chart Data Source.
			chart.ItemsSource = dataViewCollection;
			// Set Horizontal Axis label.
			chart.HorizontalAxisTitle = xAxisLabel;

			// Reguery SwapLinLogScaleCommand
			((SwapLinLogScaleCommandImpl)SwapLinLogScaleCommand).NotifyChanged();

			return true;
		}

		#region Swap Lin/Log Scale Command
		/// <summary>
		/// Command to Swap Linear/Logarithmic Axis.
		/// </summary>
		class SwapLinLogScaleCommandImpl : ICommand
		{
			MainWindow owner;

			/// <summary>
			/// Initializes a new instance of the <see cref="SwapLinLogScaleCommandImpl"/> class.
			/// </summary>
			/// <param name="owner">The owner.</param>
			public SwapLinLogScaleCommandImpl(MainWindow owner)
			{
				this.owner = owner;
			}

			#region ICommand inplementation
			/// <summary>
			/// Defines the method to be called when the command is invoked.
			/// </summary>
			/// <param name="parameter">string "Vertical" for the Vertical axis; whatever else for Horizontal axis.</param>
			public void Execute(object parameter)
			{
				bool isVertical = parameter != null && parameter is string
					&& (string)parameter == "Vertical";

				if (isVertical)
					owner.chart.VerticalScale = alternativeScale(owner.chart.VerticalScale, Extent.Height);
				else
					owner.chart.HorizontalScale = alternativeScale(owner.chart.HorizontalScale, Extent.Width);
			}

			/// <summary>
			/// Defines the method that determines whether the command can execute in its current state.
			/// </summary>
			/// <param name="parameter">string "Vertical" for the Vertical axis; whatever else for Horizontal axis.</param>
			/// <returns>
			/// <c>true</c> if this command can be executed; otherwise, <c>false</c>.
			/// </returns>
			public bool CanExecute(object parameter)
			{
				bool isVertical = parameter != null && parameter is string
					&& (string)parameter == "Vertical";

				ChartScale scale = null;
				double extent;
				if (isVertical)
				{
					scale = owner.chart.VerticalScale;
					extent = Extent.Height;
				}
				else
				{
					scale = owner.chart.HorizontalScale;
					extent = Extent.Width;
				}
				return alternativeScale(scale, extent) != null ? true : false;
			}

			public event EventHandler CanExecuteChanged;
			public void NotifyChanged()
			{
				if (CanExecuteChanged != null)
					CanExecuteChanged(this, EventArgs.Empty);
			}
			#endregion ICommand inplementation

			/// <summary>
			/// Gets given Scale alternative.
			/// </summary>
			/// <param name="scale">The scale.</param>
			/// <param name="extent">The extent.</param>
			/// <returns></returns>
			static ChartScale alternativeScale(ChartScale scale, double extent)
			{
				ChartScale newScale = null;
				if (scale is ChartLinearScale)
					newScale = new ChartLogarithmicScale(Convert.ToDouble(scale.Start)
						, Convert.ToDouble(scale.Stop), extent);
				else if (scale is ChartLogarithmicScale)
					newScale = new ChartLinearScale(Convert.ToDouble(scale.Start)
						, Convert.ToDouble(scale.Stop), extent);

				return (newScale != null && newScale.IsConsistent) ? newScale : null;
			}

			/// <summary>
			/// Gets the scale extent in pixels.
			/// </summary>
			Size Extent
			{
				get
				{
					return owner.chart.ChartAreaRenderSize.IsEmpty
						? owner.RenderSize : owner.chart.ChartAreaRenderSize;
				}
			}
		}

		ICommand swapScaleCommand;
		/// <summary>
		/// Gets the SwapLinLogScaleCommand.
		/// </summary>
		/// <value/>
		public ICommand SwapLinLogScaleCommand
		{
			get
			{
				if (swapScaleCommand == null)
					swapScaleCommand = new SwapLinLogScaleCommandImpl(this);
				return swapScaleCommand;
			}
		}
		#endregion Swap Lin/Log Scale Command

		#region OpenWPFChart.Item element events handlers
		/// <summary>
		/// Handles the MouseEnterItem event of the OpenWPFChart.Item element.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="OpenWPFChart.MouseItemEventArgs"/> 
		/// instance containing the event data.</param>
		private void chartItem_EnterItem(object sender, MouseItemEventArgs e)
		{
			Cursor = Cursors.Hand;
		}

		/// <summary>
		/// Handles the MouseLeaveItem event of the OpenWPFChart.Item element.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="OpenWPFChart.MouseItemEventArgs"/> 
		/// instance containing the event data.</param>
		private void chartItem_LeaveItem(object sender, MouseItemEventArgs e)
		{
			Cursor = null;
		}
		#endregion OpenWPFChart.Item element events handlers

		#region Menu actions handlers
		/// <summary>
		/// Handles the Click event of the MRU menu subitems.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void mru_Click(Object sender, RoutedEventArgs e)
		{
			MenuItem item = sender as MenuItem;
			if (item == null)
				return;

			MruInfo mruInfo = item.Tag as MruInfo;
			Debug.Assert(mruInfo != null, "mruInfo != null");
			bool success = false;
			switch (mruInfo.Hint)
			{
				case MruInfo.MruInfoHint.Curve:
					success = loadCurveData(mruInfo.FileName);
					break;
				case MruInfo.MruInfoHint.Column:
					success = loadColumnItemData(mruInfo.FileName);
					break;
			}
			if (!success)
				// Remove from MRU list
				mnuRecentFiles.Items.Remove(item);
		}

		/// <summary>
		/// Handles the Click event of the mnuViewInterpolator items.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void mnuViewInterpolator_Click(object sender, RoutedEventArgs e)
		{
			MenuItem mnuItem = sender as MenuItem;
			if (mnuItem == null)
				return;

			switch (mnuItem.Header.ToString())
			{
				case "_Polyline":
					setVisualCue(typeof(PolylineSampledCurve));
					break;
				case "_Bezier":
					setVisualCue(typeof(BezierSampledCurve));
					break;
				case "_Spline":
					setVisualCue(typeof(SplineSampledCurve));
					break;
			}
		}

		/// <summary>
		/// Sets the VisualCue property on all Items.
		/// </summary>
		/// <param name="cue">The cue.</param>
		private void setVisualCue(object cue)
		{
			foreach (object objItem in chart.Items)
			{
				ItemDataView itemDataView = objItem as ItemDataView;
				if (itemDataView == null)
				{
					Item item = objItem as Item;
					if (item != null)
						itemDataView = item.ItemDataView;
				}
				if (itemDataView != null)
					itemDataView.VisualCue = cue;
			}
		}

		#region Axis Properties
		/// <summary>
		/// Handles the Click event of the AxisProperties menu items.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void mnuViewAxisProperties_Click(object sender, RoutedEventArgs e)
		{
			Axis axis = null;
			if (sender == hAxisPropertiesMnuItem)
				axis = chart.HorizontalAxis;
			else if (sender == vAxisPropertiesMnuItem)
				axis = chart.VerticalAxis;
			else
				return;
			if (axis == null)
				return;

			if (axis is LinearAxis)
				setAxisProperties(axis as LinearAxis);
			else if (axis is LogarithmicAxis)
				setAxisProperties(axis as LogarithmicAxis);
			else if (axis is DateTimeAxis)
				setAxisProperties(axis as DateTimeAxis);
			else if (axis is SeriesAxis)
				setAxisProperties(axis as SeriesAxis);
		}

		/// <summary>
		/// Show LinearAxisProperties dialog.
		/// </summary>
		/// <param name="axis">The axis.</param>
		void setAxisProperties(LinearAxis axis)
		{
			AxisPropertiesDialog dlg = new AxisPropertiesDialog(axis) { Owner = this };
			if (dlg.ShowDialog() != true)
				return;

			LinearAxisDataView axisData = dlg.AxisData as LinearAxisDataView;
			axis.BeginInit();
			axis.AxisScale.Start = dlg.Start;
			axis.AxisScale.Stop = dlg.Stop;
			axis.AxisScale.Scale = dlg.Scale;
			axis.ContentLayout = axisData.ContentLayout;
			ChartLinearScale linearScale = axis.AxisScale as ChartLinearScale;
			linearScale.TickStep = axisData.TickStep;
			linearScale.LongTickAnchor = axisData.LongTickAnchor;
			linearScale.LongTickRate = axisData.LongTickRate;
			Axis.SetTickLength(chart, axisData.TickLength);
			Axis.SetLongTickLength(chart, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(chart, axisData.LabelMargin);
			Axis.SetPen(chart, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(chart, axisData.FontFamily);
			Axis.SetFontSize(chart, axisData.FontSize);
			Axis.SetFontStretch(chart, axisData.FontStretch);
			Axis.SetFontStyle(chart, axisData.FontStyle);
			Axis.SetFontWeight(chart, axisData.FontWeight);
			axis.EndInit();
		}

		/// <summary>
		/// Show LogarithmicAxisProperties dialog.
		/// </summary>
		/// <param name="axis">The axis.</param>
		void setAxisProperties(LogarithmicAxis axis)
		{
			AxisPropertiesDialog dlg = new AxisPropertiesDialog(axis) { Owner = this };
			if (dlg.ShowDialog() != true)
				return;

			LogarithmicAxisDataView axisData = dlg.AxisData as LogarithmicAxisDataView;
			axis.BeginInit();
			axis.AxisScale.Start = dlg.Start;
			axis.AxisScale.Stop = dlg.Stop;
			axis.AxisScale.Scale = dlg.Scale;
			axis.ContentLayout = axisData.ContentLayout;
			ChartLogarithmicScale linearScale = axis.AxisScale as ChartLogarithmicScale;
			linearScale.TickMask = axisData.TickMask;
			Axis.SetTickLength(chart, axisData.TickLength);
			Axis.SetLongTickLength(chart, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(chart, axisData.LabelMargin);
			Axis.SetPen(chart, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(chart, axisData.FontFamily);
			Axis.SetFontSize(chart, axisData.FontSize);
			Axis.SetFontStretch(chart, axisData.FontStretch);
			Axis.SetFontStyle(chart, axisData.FontStyle);
			Axis.SetFontWeight(chart, axisData.FontWeight);
			axis.EndInit();
		}

		/// <summary>
		/// Show DateTimeAxisProperties dialog.
		/// </summary>
		/// <param name="axis">The axis.</param>
		void setAxisProperties(DateTimeAxis axis)
		{
			AxisPropertiesDialog dlg = new AxisPropertiesDialog(axis) { Owner = this };
			if (dlg.ShowDialog() != true)
				return;

			DateTimeAxisDataView axisData = dlg.AxisData as DateTimeAxisDataView;
			axis.BeginInit();
			axis.AxisScale.Start = dlg.Start;
			axis.AxisScale.Stop = dlg.Stop;
			axis.AxisScale.Scale = dlg.Scale;
			axis.ContentLayout = axisData.ContentLayout;
			ChartDateTimeScale linearScale = axis.AxisScale as ChartDateTimeScale;
			linearScale.TickUnits = axisData.TickUnits;
			linearScale.TickStep = axisData.TickStep;
			linearScale.LongTickAnchor = axisData.LongTickAnchor;
			linearScale.LongTickRate = axisData.LongTickRate;
			Axis.SetTickLength(chart, axisData.TickLength);
			Axis.SetLongTickLength(chart, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(chart, axisData.LabelMargin);
			Axis.SetPen(chart, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(chart, axisData.FontFamily);
			Axis.SetFontSize(chart, axisData.FontSize);
			Axis.SetFontStretch(chart, axisData.FontStretch);
			Axis.SetFontStyle(chart, axisData.FontStyle);
			Axis.SetFontWeight(chart, axisData.FontWeight);
			axis.EndInit();
		}

		/// <summary>
		/// Show SeriesAxisProperties dialog.
		/// </summary>
		/// <param name="axis">The axis.</param>
		void setAxisProperties(SeriesAxis axis)
		{
			AxisPropertiesDialog dlg = new AxisPropertiesDialog(axis) { Owner = this };
			if (dlg.ShowDialog() != true)
				return;

			SeriesAxisDataView axisData = dlg.AxisData as SeriesAxisDataView;
			axis.BeginInit();
			axis.AxisScale.Start = dlg.Start;
			axis.AxisScale.Stop = dlg.Stop;
			axis.AxisScale.Scale = dlg.Scale;
			axis.ContentLayout = axisData.ContentLayout;
			ChartSeriesScale seriesScale = axis.AxisScale as ChartSeriesScale;
			seriesScale.LongTickAnchor = axisData.LongTickAnchor;
			seriesScale.LongTickRate = axisData.LongTickRate;
			Axis.SetTickLength(chart, axisData.TickLength);
			Axis.SetLongTickLength(chart, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(chart, axisData.LabelMargin);
			Axis.SetPen(chart, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(chart, axisData.FontFamily);
			Axis.SetFontSize(chart, axisData.FontSize);
			Axis.SetFontStretch(chart, axisData.FontStretch);
			Axis.SetFontStyle(chart, axisData.FontStyle);
			Axis.SetFontWeight(chart, axisData.FontWeight);
			axis.EndInit();
		}
		#endregion Axis Properties

		/// <summary>
		/// Handles the Click event of the Exit control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
		private void Exit_Click(object sender, RoutedEventArgs e)
		{
			Close();
		}
		#endregion Menu actions handlers

		#region Command Handlers
		/// <summary>
		/// Execute <see cref="ApplicationCommands.Open"/> command.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void OpenCommandHandler(object sender, ExecutedRoutedEventArgs e)
		{
			OpenFileDialog dlg = new OpenFileDialog();
			dlg.Filter = "Text Files (*.txt)|*.txt|XML Files (*.xml)|*.xml|All Files (*.*)|*.*";
			if (dlg.ShowDialog() == true)
			{
				if (e.Parameter != null && e.Parameter is string && (string)e.Parameter == "Columns")
				{
					if (loadColumnItemData(dlg.FileName))
					{
						MruInfo mruInfo = new MruInfo(dlg.FileName, MruInfo.MruInfoHint.Column);
						foreach (MenuItem item in mnuRecentFiles.Items)
						{
							if (item.Tag.Equals(mruInfo))
								return;
						}

						// Add to MRU list
						MenuItem newItem = new MenuItem()
						{
							Header = mruInfo.ToString(),
							Tag = mruInfo
						};
						newItem.Click += mru_Click;
						mnuRecentFiles.Items.Add(newItem);
					}
				}
				else
				{
					if (loadCurveData(dlg.FileName))
					{
						MruInfo mruInfo = new MruInfo(dlg.FileName, MruInfo.MruInfoHint.Curve);
						foreach (MenuItem item in mnuRecentFiles.Items)
						{
							if (item.Tag.Equals(mruInfo))
								return;
						}

						// Add to MRU list
						MenuItem newItem = new MenuItem() 
						{
							Header = mruInfo.ToString(),
							Tag = mruInfo
						};
						newItem.Click += mru_Click;
						mnuRecentFiles.Items.Add(newItem);
					}
				}
			}
		}

		#region Properties command handlers
		/// <summary>
		/// Executes <see cref="ApplicationCommands.Properties"/> command.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		void PropertiesExecutedCommandHandler(object sender, ExecutedRoutedEventArgs e)
		{
			ContextMenu mnu = (ContextMenu)FindResource("chartItemCtxMnu");
			Debug.Assert(mnu != null, "mnu != null");
			ListBoxItem listBoxItem = e.OriginalSource as ListBoxItem;
			Debug.Assert(listBoxItem != null, "listBoxItem != null");
			ItemDataView itemDataView = listBoxItem.DataContext as ItemDataView;
			Debug.Assert(itemDataView != null, "itemDataView != null");

			// ContextMenu is assigned in OpenWPFChart.Item object.
			if (mnu.Tag is ItemVisual)
			{ // Show ItemVisual Properties dialog.
				// Get GenericDataTemplateSelectorItems.
				Collection<GenericDataTemplateSelectorItem> templateSelectorItems = null;
				GenericDataTemplateSelector templateSelector = chart.ItemTemplateSelector as GenericDataTemplateSelector;
				if (templateSelector != null)
					templateSelectorItems = templateSelector.SelectorItems;

				// Show the dialog.
				ItemPropertiesDialog dlg = new ItemPropertiesDialog(itemDataView, templateSelectorItems) { Owner = this };
				if (dlg.ShowDialog() == true)
				{
					// Curve Name
					itemDataView.ItemData.ItemName = dlg.ItemName;

					#region HorizontalScale
					ChartScale hScale = itemDataView.HorizontalScale;
					hScale.Start = dlg.HorizontalScaleStart;
					hScale.Stop = dlg.HorizontalScaleStop;
					hScale.Scale = dlg.HorizontalScaleScale;
					chart.HorizontalScale = hScale;
					if ((hScale.GetType() == typeof(ChartLinearScale)
							&& dlg.HorizontalScaleVeriety == ChartScaleVerieties.Logarithmic)
						|| (hScale.GetType() == typeof(ChartLogarithmicScale)
							&& dlg.HorizontalScaleVeriety == ChartScaleVerieties.Linear))
					{
						SwapLinLogScaleCommand.Execute(null);
					}
					#endregion HorizontalScale

					#region VerticalScale
					ChartScale vScale = itemDataView.VerticalScale;
					vScale.Start = dlg.VerticalScaleStart;
					vScale.Stop = dlg.VerticalScaleStop;
					vScale.Scale = dlg.VerticalScaleScale;
					chart.VerticalScale = vScale;
					if ((vScale.GetType() == typeof(ChartLinearScale)
							&& dlg.VerticalScaleVeriety == ChartScaleVerieties.Logarithmic)
						|| (vScale.GetType() == typeof(ChartLogarithmicScale)
							&& dlg.VerticalScaleVeriety == ChartScaleVerieties.Linear))
					{
						SwapLinLogScaleCommand.Execute("Vertical");
					}
					#endregion HorizontalScale

					// Curve Color
					CurveDataView curveDataView = itemDataView as CurveDataView;
					if (curveDataView != null)
					{
						Color color = Colors.Black;
						SolidColorBrush solidColorBrush = curveDataView.Pen.Brush as SolidColorBrush;
						if (solidColorBrush != null)
							color = solidColorBrush.Color;
						if (solidColorBrush == null || dlg.CurveColor != color)
							curveDataView.Pen = new Pen(new SolidColorBrush(dlg.CurveColor), 1);
					}

					// PointMarkerVisibility
					IPointMarker iPointMarker = curveDataView as IPointMarker;
					if (iPointMarker != null)
						iPointMarker.PointMarkerVisible = dlg.PointMarkerVisible;

					// VisualCue
					if (dlg.VisualCue != null)
						itemDataView.VisualCue = dlg.VisualCue;
				}
				e.Handled = true;
			}
			else if (mnu.Tag is ChartPointVisual)
			{ // Show ChartPointVisual Properties dialog.
				IPointMarker iPointMarker = itemDataView as IPointMarker;
				if (iPointMarker != null)
				{
					ChartPointPropertiesDialog dlg = new ChartPointPropertiesDialog(iPointMarker.PointMarker)
						{ Owner = this };
					if (dlg.ShowDialog() == true)
					{
						if (dlg.PointMarker != iPointMarker.PointMarker)
						{
							iPointMarker.PointMarker = dlg.PointMarker;
						}
					}
				}
				e.Handled = true;
			}
		}

		/// <summary>
		/// Checks the <see cref="ApplicationCommands.Properties"/> command can be executed.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
		private void PropertiesCanExecuteCommandHandler(object sender, CanExecuteRoutedEventArgs e)
		{
			ListBoxItem listBoxItem = e.OriginalSource as ListBoxItem;
			if (listBoxItem != null)
			{
				ItemDataView itemDataView = listBoxItem.DataContext as ItemDataView;
				if (itemDataView != null)
				{
					e.CanExecute = true;
					return;
				}
			}
			e.CanExecute = false;
		}
		#endregion Properties command handlers

		/// <summary>
		/// Execute <see cref="NavigationCommands.Zoom"/> command.
		/// </summary>
		/// <param name="sender">The sender.</param>
		/// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
		private void ZoomCommandHandler(object sender, ExecutedRoutedEventArgs e)
		{
			double zoom = 1.2;
			if (e.Parameter != null)
			{
				try
				{
					zoom = Convert.ToDouble(e.Parameter);
				}
				catch (Exception ex)
				{
					Trace.WriteLine("ZoomCommandHandler " + ex.Message);
					return;
				}
			}

			if (zoom == 0.0)
				return;
			if (zoom < 0.0)
				zoom = -1.0 / zoom;

			chart.HorizontalScale.Scale *= zoom;
			chart.VerticalScale.Scale *= zoom;
		}
		#endregion Command Handlers
	}
}

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

Comments and Discussions