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