Click here to Skip to main content
Click here to Skip to main content
Add your own
alternative version

OpenWPFChart: Assembling Charts from Components. Part II - Controls

, 26 Mar 2009 CPOL
Chart controls composed from Chart Parts
SourceCode.zip
trunk
ChartControls
ChartControls.csproj.user
OpenWPFChart.Chart.Icon.png
OpenWPFChart.WellLogChart.Icon.png
Properties
Themes
ChartHelpers
AxisPropertiesDialog
ChartHelpers.csproj.user
ChartScaleControl
FontChooser
ItemPropertiesDialog
Properties
ChartParts
Axes
ChartParts.csproj.user
Grid
Items
Data
DataView
Elements
Visuals
NumericalRecipes
Properties
Scales
SampleDataFiles
WellLog
Samples
ControlSamples
ColumnChartControlSample
Properties
Settings.settings
CurveChartControlSample
Properties
Settings.settings
r3xyqstb.tmp_proj
WellLogControlSample
Properties
Settings.settings
DirectCompositionSamples
BasicSample
Properties
Settings.settings
TemperatureSample
Properties
Settings.settings
WellLogSample
Properties
Settings.settings
// <copyright file="MainWindow.xaml.cs" company="Oleg V. Polikarpotchkin">
// Copyright © 2008 Oleg V. Polikarpotchkin. All Right Reserved
// </copyright>
// <author>Oleg V. Polikarpotchkin</author>
// <email>ov-p@yandex.ru</email>
// <date>2008-12-23</date>
// <summary>OpenWPFChart library.
// Basic Sample: Chart with two axes is composed in MainWindow.
// </summary>
// <revision>$Id: MainWindow.xaml.cs 19488 2009-03-23 08:40:46Z unknown $</revision>

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

namespace BasicSample
{
	/// <summary>
	/// Basic Sample main Window.
	/// </summary>
	public partial class MainWindow : Window
	{
		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)
			{
				foreach (string fileName in mru)
				{
					MenuItem item = new MenuItem(){ Header = fileName };
					item.Click += mnuFileMRU_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.Header as string);
				}
			}
			Properties.Settings.Default.MRU = mru;

			Properties.Settings.Default.Save();
		}

		#region Properties
		#region Dependency Properties
		#region HorizontalScale
		/// <summary>
		/// Identifies the HorizontalScale dependency property.
		/// </summary>
		public static readonly DependencyProperty HorizontalScaleProperty
			= DependencyProperty.Register("HorizontalScale", typeof(ChartScale), typeof(MainWindow)
				, new FrameworkPropertyMetadata(null
					, FrameworkPropertyMetadataOptions.AffectsMeasure
						| FrameworkPropertyMetadataOptions.AffectsRender
					)
				);
		/// <summary>
		/// Gets or sets the HorizontalScale property.
		/// </summary>
		/// <value/>
		public ChartScale HorizontalScale
		{
			get { return (ChartScale)GetValue(HorizontalScaleProperty); }
			set { SetValue(HorizontalScaleProperty, value); }
		}
		#endregion HorizontalScale

		#region VerticalScale
		/// <summary>
		/// Identifies the VerticalScale dependency property.
		/// </summary>
		public static readonly DependencyProperty VerticalScaleProperty
			= DependencyProperty.Register("VerticalScale", typeof(ChartScale), typeof(MainWindow)
				, new FrameworkPropertyMetadata(null
					, FrameworkPropertyMetadataOptions.AffectsMeasure
						| FrameworkPropertyMetadataOptions.AffectsRender
					)
				);
		/// <summary>
		/// Gets or sets the VerticalScale property.
		/// </summary>
		/// <value/>
		public ChartScale VerticalScale
		{
			get { return (ChartScale)GetValue(VerticalScaleProperty); }
			set { SetValue(VerticalScaleProperty, value); }
		}
		#endregion VerticalScale
		#endregion Dependency Properties

		#region Axes
		/// <summary>
		/// Gets the horizontal axis.
		/// </summary>
		/// <value>The horizontal axis.</value>
		Axis HorizontalAxis
		{
			get { return findAxis(hAxisHost); }
		}

		/// <summary>
		/// Gets the vertical axis.
		/// </summary>
		/// <value>The vertical axis.</value>
		Axis VerticalAxis
		{
			get { return findAxis(vAxisHost); }
		}

		/// <summary>
		/// Finds an axis in its container Visual Tree.
		/// </summary>
		/// <param name="parent">The parent.</param>
		/// <returns></returns>
		Axis findAxis(DependencyObject parent)
		{
			Axis axis = parent as Axis;
			if (axis != null)
				return axis;
			for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); ++i)
			{
				DependencyObject item = VisualTreeHelper.GetChild(parent, i);
				axis = findAxis(item);
				if (axis != null)
					return axis;
			}
			return null;
		}
		#endregion Axes
		#endregion Properties

		#region Scales Manipulations
		#region Swap Lin/Log Scale Command
		/// <summary>
		/// Command to Swap Linear/Logarithmic Axis.
		/// </summary>
		class SwapLinLogScaleCommandClass : ICommand
		{
			public delegate void ExecuteDelegate(object parameter);
			public delegate bool CanExecuteDelegate(object parameter);

			ExecuteDelegate execute;
			CanExecuteDelegate canExecute;

			public SwapLinLogScaleCommandClass(ExecuteDelegate executeDelegate
				, CanExecuteDelegate canExecuteDelegate)
			{
				execute = executeDelegate;
				canExecute = canExecuteDelegate;
			}

			public void Execute(object parameter)
			{
				execute(parameter);
			}

			public bool CanExecute(object parameter)
			{
				return canExecute(parameter);
			}

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

		ICommand swapScaleCommand;
		/// <summary>
		/// Gets the SwapLinLogScaleCommand.
		/// </summary>
		/// <value/>
		public ICommand SwapLinLogScaleCommand
		{
			get
			{
				if (swapScaleCommand == null)
				{
					swapScaleCommand 
						= new SwapLinLogScaleCommandClass(SwapScale, CanSwapScale);
				}
				return swapScaleCommand;
			}
		}
		/// <summary>
		/// SwapLinLogScaleCommandClass CanExecute handler.
		/// </summary>
		/// <param name="parameter">string "Vertical" for the Vertical axis; whatever els for Horizontal axis.</param>
		/// <returns>
		/// 	<c>true</c> if CanExecute; otherwise, <c>false</c>.
		/// </returns>
		bool CanSwapScale(object parameter)
		{
			bool isVertical = parameter != null && parameter is string 
				&& (string)parameter == "Vertical";
			ChartScale scale = null;
			double extent;
			if (isVertical)
			{
				scale = VerticalScale;
				extent = chart.ActualHeight > 0 ? chart.ActualHeight : ActualHeight;
			}
			else
			{
				scale = HorizontalScale;
				extent = chart.ActualWidth > 0 ? chart.ActualWidth : ActualWidth;
			}
			ChartScale newScale = alternativeScale(scale, extent);
			return (newScale != null && newScale.IsConsistent) ? true : false;
		}
		/// <summary>
		/// SwapLinLogScaleCommandClass Execute handler.
		/// </summary>
		/// <param name="parameter">string "Vertical" for the Vertical axis; whatever els for Horizontal axis.</param>
		void SwapScale(object parameter)
		{
			bool isVertical = parameter != null && parameter is string 
				&& (string)parameter == "Vertical";
			if (isVertical)
				SwapVerticalScale(VerticalScale);
			else
				SwapHoirizontalScale(HorizontalScale);
		}

		void SwapVerticalScale(ChartScale scaleToSwap)
		{
			double extent = chart.ActualHeight > 0 ? chart.ActualHeight : ActualHeight;
			ChartScale scale = alternativeScale(scaleToSwap, extent);
			foreach (var obj in chart.Items)
			{
				ItemDataView itemDataView = obj as ItemDataView;
				if (itemDataView == null)
				{
					Item item = obj as Item;
					if (item != null)
						itemDataView = item.ItemDataView;
				}
				if (itemDataView != null)
					itemDataView.VerticalScale = scale;
			}
			VerticalScale = scale;
		}

		void SwapHoirizontalScale(ChartScale scaleToSwap)
		{
			double extent = chart.ActualWidth > 0 ? chart.ActualWidth : ActualWidth;
			ChartScale scale = alternativeScale(scaleToSwap, extent);
			foreach (var obj in chart.Items)
			{
				ItemDataView itemDataView = obj as ItemDataView;
				if (itemDataView == null)
				{
					Item item = obj as Item;
					if (item != null)
						itemDataView = item.ItemDataView;
				}
				if (itemDataView != null)
					itemDataView.HorizontalScale = scale;
			}
			HorizontalScale = scale;
		}

		#endregion Swap Lin/Log Scale Command

		/// <summary>
		/// Gets given Scale alternative.
		/// </summary>
		/// <param name="scale">The scale.</param>
		/// <param name="extent">The extent.</param>
		/// <returns></returns>
		ChartScale alternativeScale(ChartScale scale, double extent)
		{
			if (scale is ChartLinearScale)
				return alternativeScale(scale as ChartLinearScale, extent);
			else if (scale is ChartLogarithmicScale)
				return alternativeScale(scale as ChartLogarithmicScale, extent);
			return null;
		}

		/// <summary>
		/// Gets given ChartLinearScale alternative.
		/// </summary>
		/// <param name="scale">The scale.</param>
		/// <param name="extent">The extent.</param>
		/// <returns></returns>
		ChartScale alternativeScale(ChartLinearScale scale, double extent)
		{
			ChartLogarithmicScale newScale = new ChartLogarithmicScale(Convert.ToDouble(scale.Start)
				, Convert.ToDouble(scale.Stop), extent);
			return newScale.IsConsistent ? newScale : null;
		}

		/// <summary>
		/// Gets given ChartLogarithmicScale alternative.
		/// </summary>
		/// <param name="scale">The scale.</param>
		/// <param name="extent">The extent.</param>
		/// <returns></returns>
		ChartScale alternativeScale(ChartLogarithmicScale scale, double extent)
		{
			ChartLinearScale newScale = new ChartLinearScale(Convert.ToDouble(scale.Start)
				, Convert.ToDouble(scale.Stop), extent);
			return newScale.IsConsistent ? newScale : null;
		}
		#endregion Scales Manipulations

		/// <summary>
		/// Loads CurveData from the file.
		/// </summary>
		/// <param name="fileName">Name of the file.</param>
		/// <returns><c>true</c> if data loaded; otherwise <c>false</c>.</returns>
		/// <exception cref="Exception">Misc IO and file parser exceptions.</exception>
		bool loadCurveData(string fileName)
		{
			ObservableCollection<ItemData> dataCollection = null;
			FileInfo fi = new FileInfo(fileName);
			try
			{
				if (fi.Extension.ToLower() == ".txt")
					dataCollection = SpaceSeparatedDataFileParser.Parse(fileName);
				else if (fi.Extension.ToLower() == ".xml")
					dataCollection = XMLDataFileParser.Parse(fileName);

				if (dataCollection == null || dataCollection.Count == 0)
				{
					MessageBox.Show("Data wasn't loaded");
					return false;
				}
			}
			catch (Exception ex)
			{
				MessageBox.Show(ex.Message);
				return false;
			}

			// Set X-Chart Scale
			ChartScale horizontalScale = null;
			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;
				horizontalScale = new ChartLinearScale(xMin, xMax, chart.ActualWidth > 0 ? chart.ActualWidth : 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;
				horizontalScale = new ChartDateTimeScale(xMin, xMax, chart.ActualWidth > 0 ? chart.ActualWidth : 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;
				horizontalScale = new ChartSeriesScale(from pt in points select pt.X
					, xMin, xMax, chart.ActualWidth > 0 ? chart.ActualWidth : 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;
				horizontalScale = new ChartLinearScale(xMin, xMax, chart.ActualWidth > 0 ? chart.ActualWidth : ActualWidth);
			}
			else
			{
				MessageBox.Show(string.Format("There is no appropriate data in the {0} file", fileName)
					, "Open Data File");
				return false;
			}

			if (!horizontalScale.IsConsistent)
				throw new ArgumentException(string.Format("Invalid X scale in {0} file", fileName));
			HorizontalScale = horizontalScale;

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

			ChartScale verticalScale = new ChartLinearScale(yMax, yMin
				, chart.ActualHeight > 0 ? chart.ActualHeight : ActualHeight);
			if (!verticalScale.IsConsistent)
				throw new ArgumentException(string.Format("Invalid Y scale in {0} file", fileName));
			VerticalScale = verticalScale;

			// 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 = this.HorizontalScale,
						VerticalScale = this.VerticalScale,
						PointMarker = pointMarker
					};

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

					dataViewCollection.Add(dataView);
				}
			}

			DataContext = dataViewCollection;

			(SwapLinLogScaleCommand as SwapLinLogScaleCommandClass).NotifyChanged();

			return true;
		}

		#region Chart Events Handlers
		/// <summary>
		/// Handles the SelectionChanged event of the ListBox (chart) control.
		/// </summary>
		/// <param name="sender">The source of the event.</param>
		/// <param name="e">The <see cref="System.Windows.Controls.SelectionChangedEventArgs"/> instance containing the event data.</param>
		private void chart_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
		{
			Trace.WriteLine(string.Format("***** MainWindow.chart_SelectionChanged Source={0} OriginalSource={0}", e.Source, e.OriginalSource));
		}

		/// <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 item_Enter(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 item_Leave(object sender, MouseItemEventArgs e)
		{
			Cursor = null;
		}

		/// <summary>
		/// Handles the VisualCueChanged event of the OpenWPFChart.Item element.
		/// <para>Resets the Chart ItemTemplateSelector.</para>
		/// </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 item_VisualCueChanged(object sender, RoutedEventArgs e)
		{
			DataTemplateSelector old = chart.ItemTemplateSelector;
			chart.ItemTemplateSelector = null;
			chart.ItemTemplateSelector = old;
		}
		#endregion Chart 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 mnuFileMRU_Click(Object sender, RoutedEventArgs e)
		{
			MenuItem item = sender as MenuItem;
			if (item == null)
				return;
			string fileName = item.Header as string;
			if (!loadCurveData(fileName))
			{ // Remove from MRU list
				mnuRecentFiles.Items.Remove(item);
			}
		}

		/// <summary>
		/// Prints the "panel".
		/// Handles the Click event of the mnuFilePrint item.
		/// </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 mnuFilePrint_Click(object sender, RoutedEventArgs e)
		{
			//PrintDocumentImageableArea area = null;
			//XpsDocumentWriter xpsdw = PrintQueue.CreateXpsDocumentWriter(ref area);
			//if (xpsdw != null)
			//{
			//    xpsdw.Write(panel);
			//}

			PrintDialog dlg = new System.Windows.Controls.PrintDialog();
			if (dlg.ShowDialog() == true)
			{
				// Get selected printer capabilities.
				PrintCapabilities capabilities = dlg.PrintQueue.GetPrintCapabilities(dlg.PrintTicket);

				// Get scale of the print wrt to screen of Chart.
				double scale = Math.Min(capabilities.PageImageableArea.ExtentWidth / panel.ActualWidth
					, capabilities.PageImageableArea.ExtentHeight / panel.ActualHeight);

				// Save old transform.
				Transform savedTransform = panel.LayoutTransform;
				// Scale the Chart.
				panel.LayoutTransform = new ScaleTransform(scale, scale);

				// Get the size of the printer page.
				Size sz = new Size(capabilities.PageImageableArea.ExtentWidth
					, capabilities.PageImageableArea.ExtentHeight);

				// Update the layout of the Chart to the printer page size.
				panel.Measure(sz);
				panel.Arrange(new Rect(new Point(capabilities.PageImageableArea.OriginWidth
					, capabilities.PageImageableArea.OriginHeight), sz));

				// Print the Chart to printer to fit on the one page.
				dlg.PrintVisual(panel, "Print the Chart");
				
				// Restore old transform.
				panel.LayoutTransform = savedTransform;
			}
		}

		/// <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 mnuFileExit_Click(object sender, RoutedEventArgs e)
		{
			Close();
		}

		/// <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 ItemDataView items of SampledCurveDataView type.
		/// </summary>
		/// <param name="cue">The cue.</param>
		private void setVisualCue(object cue)
		{
			ObservableCollection<ItemDataView> dataViewCollection = DataContext as ObservableCollection<ItemDataView>;
			if (dataViewCollection == null)
				return;
			foreach (ItemDataView item in dataViewCollection)
			{
				SampledCurveDataView sampledCurveDataView = item as SampledCurveDataView;
				if (sampledCurveDataView != null)
					sampledCurveDataView.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 = HorizontalAxis;
			else if (sender == vAxisPropertiesMnuItem)
				axis = 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(panel, axisData.TickLength);
			Axis.SetLongTickLength(panel, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(panel, axisData.LabelMargin);
			Axis.SetPen(panel, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(panel, axisData.FontFamily);
			Axis.SetFontSize(panel, axisData.FontSize);
			Axis.SetFontStretch(panel, axisData.FontStretch);
			Axis.SetFontStyle(panel, axisData.FontStyle);
			Axis.SetFontWeight(panel, 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(panel, axisData.TickLength);
			Axis.SetLongTickLength(panel, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(panel, axisData.LabelMargin);
			Axis.SetPen(panel, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(panel, axisData.FontFamily);
			Axis.SetFontSize(panel, axisData.FontSize);
			Axis.SetFontStretch(panel, axisData.FontStretch);
			Axis.SetFontStyle(panel, axisData.FontStyle);
			Axis.SetFontWeight(panel, 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(panel, axisData.TickLength);
			Axis.SetLongTickLength(panel, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(panel, axisData.LabelMargin);
			Axis.SetPen(panel, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(panel, axisData.FontFamily);
			Axis.SetFontSize(panel, axisData.FontSize);
			Axis.SetFontStretch(panel, axisData.FontStretch);
			Axis.SetFontStyle(panel, axisData.FontStyle);
			Axis.SetFontWeight(panel, 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(panel, axisData.TickLength);
			Axis.SetLongTickLength(panel, axisData.LongTickLength);
			axis.LabelFormat = axisData.LabelFormat;
			Axis.SetLabelMargin(panel, axisData.LabelMargin);
			Axis.SetPen(panel, new Pen()
			{
				Brush = new SolidColorBrush(axisData.PenColor),
				Thickness = axisData.PenThickness
			});
			Axis.SetFontFamily(panel, axisData.FontFamily);
			Axis.SetFontSize(panel, axisData.FontSize);
			Axis.SetFontStretch(panel, axisData.FontStretch);
			Axis.SetFontStyle(panel, axisData.FontStyle);
			Axis.SetFontWeight(panel, axisData.FontWeight);
			axis.EndInit();
		}
		#endregion Axis Properties
		#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 OpenExecutedCommandHandler(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 (loadCurveData(dlg.FileName))
				{
					// Add to MRU list
					foreach (MenuItem item in mnuRecentFiles.Items)
					{
						if (dlg.FileName == item.Header as string)
							return;
					}

					MenuItem newItem = new MenuItem() { Header = dlg.FileName };
					newItem.Click += mnuFileMRU_Click;
					mnuRecentFiles.Items.Add(newItem);
				}
			}
		}

		/// <summary>
		/// Executes <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 ZoomExecutedCommandHandler(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;

			HorizontalScale.Scale *= zoom;
			VerticalScale.Scale *= zoom;
			foreach (ItemDataView item in chart.Items)
			{
				item.HorizontalScale.Scale *= zoom;
				item.VerticalScale.Scale *= zoom;
			}
		}

		#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 CurveProperties 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;
					if ((hScale.GetType() == typeof(ChartLinearScale)
							&& dlg.HorizontalScaleVeriety == ChartScaleVerieties.Logarithmic)
						|| (hScale.GetType() == typeof(ChartLogarithmicScale)
							&& dlg.HorizontalScaleVeriety == ChartScaleVerieties.Linear))
					{
						SwapHoirizontalScale(hScale);
					}
					#endregion HorizontalScale

					#region VerticalScale
					ChartScale vScale = itemDataView.VerticalScale;
					vScale.Start = dlg.VerticalScaleStart;
					vScale.Stop = dlg.VerticalScaleStop;
					vScale.Scale = dlg.VerticalScaleScale;
					if ((vScale.GetType() == typeof(ChartLinearScale)
							&& dlg.VerticalScaleVeriety == ChartScaleVerieties.Logarithmic)
						|| (vScale.GetType() == typeof(ChartLogarithmicScale)
							&& dlg.VerticalScaleVeriety == ChartScaleVerieties.Linear))
					{
						SwapVerticalScale(vScale);
					}
					#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 ChartPointProperties 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;
			}
		}
		#endregion Properties command handlers
		#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)

Share

About the Author

Oleg V. Polikarpotchkin
Team Leader
Russian Federation Russian Federation
No Biography provided

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 26 Mar 2009
Article Copyright 2009 by Oleg V. Polikarpotchkin
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid