// (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.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; using System.Windows.Data; namespace System.Windows.Controls.DataVisualization.Charting { /// /// A dynamic series with axes and only one legend item and style for all /// data points. /// /// Preview public abstract class DataPointSingleSeriesWithAxes : DataPointSeriesWithAxes, IRequireGlobalSeriesIndex { /// /// Name of the ActualDataPointStyle property. /// protected const string ActualDataPointStyleName = "ActualDataPointStyle"; /// /// Gets the single legend item associated with the series. /// protected LegendItem LegendItem { get { if (null == _legendItem) { _legendItem = CreateLegendItem(this); LegendItems.Add(_legendItem); } return _legendItem; } } /// /// Stores the LegendItem for the series. /// private LegendItem _legendItem; /// /// Gets the Palette-dispensed ResourceDictionary for the Series. /// protected ResourceDictionary PaletteResources { get; private set; } /// /// Gets or sets a value indicating whether a custom title is in use. /// private bool CustomTitleInUse { get; set; } /// /// DataPointStyleProperty property changed handler. /// /// Old value. /// New value. protected override void OnDataPointStylePropertyChanged(Style oldValue, Style newValue) { // Propagate change ActualDataPointStyle = newValue; base.OnDataPointStylePropertyChanged(oldValue, newValue); } #region protected Style ActualDataPointStyle /// /// Gets or sets the actual style used for the data points. /// protected Style ActualDataPointStyle { get { return GetValue(ActualDataPointStyleProperty) as Style; } set { SetValue(ActualDataPointStyleProperty, value); } } /// /// Identifies the ActualDataPointStyle dependency property. /// protected static readonly DependencyProperty ActualDataPointStyleProperty = DependencyProperty.Register( ActualDataPointStyleName, typeof(Style), typeof(DataPointSingleSeriesWithAxes), null); #endregion protected Style ActualDataPointStyle #region protected Style ActualLegendItemStyle /// /// Gets or sets the actual style used for the legend item. /// protected Style ActualLegendItemStyle { get { return GetValue(ActualLegendItemStyleProperty) as Style; } set { SetValue(ActualLegendItemStyleProperty, value); } } /// /// Identifies the ActualLegendItemStyle dependency property. /// protected static readonly DependencyProperty ActualLegendItemStyleProperty = DependencyProperty.Register( ActualLegendItemStyleName, typeof(Style), typeof(DataPointSeries), null); #endregion protected Style ActualLegendItemStyle /// /// Called when the value of the LegendItemStyle property changes. /// /// Old value. /// New value. protected override void OnLegendItemStylePropertyChanged(Style oldValue, Style newValue) { // Propagate change ActualLegendItemStyle = newValue; base.OnLegendItemStylePropertyChanged(oldValue, newValue); } #region public int? GlobalSeriesIndex /// /// Gets the index of the series in the Parent's series collection. /// public int? GlobalSeriesIndex { get { return (int?)GetValue(GlobalSeriesIndexProperty); } private set { SetValue(GlobalSeriesIndexProperty, value); } } /// /// Identifies the GlobalSeriesIndex dependency property. /// public static readonly DependencyProperty GlobalSeriesIndexProperty = DependencyProperty.Register( "GlobalSeriesIndex", typeof(int?), typeof(Series), new PropertyMetadata(new int?(), OnGlobalSeriesIndexPropertyChanged)); /// /// GlobalSeriesIndexProperty property changed handler. /// /// Series that changed its Index. /// Event arguments. 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); } /// /// GlobalSeriesIndexProperty property changed handler. /// /// Old value. /// New value. [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) { if (!CustomTitleInUse && (null == GetBindingExpression(TitleProperty))) { Title = newValue.HasValue ? string.Format(CultureInfo.CurrentCulture, Properties.Resources.Series_OnGlobalSeriesIndexPropertyChanged_UntitledSeriesFormatString, newValue.Value + 1) : null; // Setting Title will set CustomTitleInUse; reset it now CustomTitleInUse = false; } } #endregion public int? GlobalSeriesIndex /// /// Called when the Title property changes. /// /// Old value of the Title property. /// New value of the Title property. protected override void OnTitleChanged(object oldValue, object newValue) { // Title property is being set, so a custom Title is in use CustomTitleInUse = true; } /// /// Initializes a new instance of the DataPointSingleSeriesWithAxes class. /// protected DataPointSingleSeriesWithAxes() { } /// /// Returns the custom ResourceDictionary to use for necessary resources. /// /// /// ResourceDictionary to use for necessary resources. /// [SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This property does more work than get functions typically do.")] protected abstract IEnumerator GetResourceDictionaryEnumeratorFromHost(); /// /// Insert grid containing data point used for legend item into the /// plot area. /// /// The old plot area. /// The new plot area. protected override void OnPlotAreaChanged(Panel oldValue, Panel newValue) { if (newValue != null) { CreateLegendItemDataPoint(); } base.OnPlotAreaChanged(oldValue, newValue); } /// /// When the series host property is set retrieves a style to use for all the /// data points. /// /// The old series host value. /// The new series host value. protected override void OnSeriesHostPropertyChanged(ISeriesHost oldValue, ISeriesHost newValue) { base.OnSeriesHostPropertyChanged(oldValue, newValue); if (oldValue != null) { oldValue.ResourceDictionariesChanged -= new EventHandler(SeriesHostResourceDictionariesChanged); } if (newValue != null) { newValue.ResourceDictionariesChanged += new EventHandler(SeriesHostResourceDictionariesChanged); DispensedResourcesChanging(); } } /// /// Creates the LegendItem Control if conditions are right. /// private void CreateLegendItemDataPoint() { DataPoint dataPoint = CreateDataPoint(); if (null != PlotArea) { // Bounce into the visual tree to get default Style applied PlotArea.Children.Add(dataPoint); PlotArea.Children.Remove(dataPoint); } dataPoint.SetBinding(DataPoint.StyleProperty, new Binding(ActualDataPointStyleName) { Source = this }); // Start DataContext null to avoid Binding warnings in the output window LegendItem.DataContext = null; #if !SILVERLIGHT if (null == LegendItem.Parent) { #endif LegendItem.Loaded += delegate { // Wait for Loaded to set the DataPoint LegendItem.DataContext = dataPoint; }; #if !SILVERLIGHT } else { LegendItem.DataContext = dataPoint; } #endif } /// /// Called after data points have been loaded from the items source. /// /// New active data points. /// Old inactive data points. protected override void OnDataPointsChanged(IList newDataPoints, IList oldDataPoints) { base.OnDataPointsChanged(newDataPoints, oldDataPoints); 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); } } } /// /// Sets the style of the data point to the single style used for all /// data points. /// /// The data point to apply the style to. /// /// The object associated with the data point. /// protected override void PrepareDataPoint(DataPoint dataPoint, object dataContext) { dataPoint.SetBinding(DataPoint.StyleProperty, new Binding(ActualDataPointStyleName) { Source = this }); base.PrepareDataPoint(dataPoint, dataContext); } /// /// This method updates the global series index property. /// /// The global index of the series. public void GlobalSeriesIndexChanged(int? globalIndex) { this.GlobalSeriesIndex = globalIndex; } /// /// Handles the SeriesHost's ResourceDictionariesChanged event. /// /// ISeriesHost instance. /// Event args. private void SeriesHostResourceDictionariesChanged(object sender, EventArgs e) { DispensedResourcesChanging(); } /// /// Processes the change of the DispensedResources property. /// private void DispensedResourcesChanging() { if (null != PaletteResources) { Resources.MergedDictionaries.Remove(PaletteResources); PaletteResources = null; } using (IEnumerator enumerator = GetResourceDictionaryEnumeratorFromHost()) { if (enumerator.MoveNext()) { PaletteResources = #if SILVERLIGHT enumerator.Current.ShallowCopy(); #else enumerator.Current; #endif Resources.MergedDictionaries.Add(PaletteResources); } } CreateLegendItemDataPoint(); ActualDataPointStyle = DataPointStyle ?? (Resources[DataPointStyleName] as Style); ActualLegendItemStyle = LegendItemStyle ?? (Resources[LegendItemStyleName] as Style); Refresh(); } } }