All the controls missing in WPF. Over 1 million downloads.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

352 lines
14 KiB

// (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
{
/// <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>
/// Name of the ActualDataPointStyle property.
/// </summary>
protected const string ActualDataPointStyleName = "ActualDataPointStyle";
/// <summary>
/// Gets the single legend item associated with the series.
/// </summary>
protected LegendItem LegendItem
{
get
{
if (null == _legendItem)
{
_legendItem = CreateLegendItem(this);
LegendItems.Add(_legendItem);
}
return _legendItem;
}
}
/// <summary>
/// Stores the LegendItem for the series.
/// </summary>
private LegendItem _legendItem;
/// <summary>
/// Gets the Palette-dispensed ResourceDictionary for the Series.
/// </summary>
protected ResourceDictionary PaletteResources { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether a custom title is in use.
/// </summary>
private bool CustomTitleInUse { get; set; }
/// <summary>
/// DataPointStyleProperty property changed handler.
/// </summary>
/// <param name="oldValue">Old value.</param>
/// <param name="newValue">New value.</param>
protected override void OnDataPointStylePropertyChanged(Style oldValue, Style newValue)
{
// Propagate change
ActualDataPointStyle = newValue;
base.OnDataPointStylePropertyChanged(oldValue, newValue);
}
#region protected Style ActualDataPointStyle
/// <summary>
/// Gets or sets the actual style used for the data points.
/// </summary>
protected Style ActualDataPointStyle
{
get { return GetValue(ActualDataPointStyleProperty) as Style; }
set { SetValue(ActualDataPointStyleProperty, value); }
}
/// <summary>
/// Identifies the ActualDataPointStyle dependency property.
/// </summary>
protected static readonly DependencyProperty ActualDataPointStyleProperty =
DependencyProperty.Register(
ActualDataPointStyleName,
typeof(Style),
typeof(DataPointSingleSeriesWithAxes),
null);
#endregion protected Style ActualDataPointStyle
#region protected Style ActualLegendItemStyle
/// <summary>
/// Gets or sets the actual style used for the legend item.
/// </summary>
protected Style ActualLegendItemStyle
{
get { return GetValue(ActualLegendItemStyleProperty) as Style; }
set { SetValue(ActualLegendItemStyleProperty, value); }
}
/// <summary>
/// Identifies the ActualLegendItemStyle dependency property.
/// </summary>
protected static readonly DependencyProperty ActualLegendItemStyleProperty =
DependencyProperty.Register(
ActualLegendItemStyleName,
typeof(Style),
typeof(DataPointSeries),
null);
#endregion protected Style ActualLegendItemStyle
/// <summary>
/// Called when the value of the LegendItemStyle property changes.
/// </summary>
/// <param name="oldValue">Old value.</param>
/// <param name="newValue">New value.</param>
protected override void OnLegendItemStylePropertyChanged(Style oldValue, Style newValue)
{
// Propagate change
ActualLegendItemStyle = newValue;
base.OnLegendItemStylePropertyChanged(oldValue, newValue);
}
#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(new int?(), 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>
[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
/// <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;
}
/// <summary>
/// Initializes a new instance of the DataPointSingleSeriesWithAxes class.
/// </summary>
protected DataPointSingleSeriesWithAxes()
{
}
/// <summary>
/// Returns the custom ResourceDictionary to use for necessary resources.
/// </summary>
/// <returns>
/// ResourceDictionary to use for necessary resources.
/// </returns>
[SuppressMessage("Microsoft.Design", "CA1024:UsePropertiesWhereAppropriate", Justification = "This property does more work than get functions typically do.")]
protected abstract IEnumerator<ResourceDictionary> GetResourceDictionaryEnumeratorFromHost();
/// <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(Panel oldValue, Panel 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 (oldValue != null)
{
oldValue.ResourceDictionariesChanged -= new EventHandler(SeriesHostResourceDictionariesChanged);
}
if (newValue != null)
{
newValue.ResourceDictionariesChanged += new EventHandler(SeriesHostResourceDictionariesChanged);
DispensedResourcesChanging();
}
}
/// <summary>
/// Creates the LegendItem Control if conditions are right.
/// </summary>
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
}
/// <summary>
/// Called after data points have been loaded from the items source.
/// </summary>
/// <param name="newDataPoints">New active data points.</param>
/// <param name="oldDataPoints">Old inactive data points.</param>
protected override void OnDataPointsChanged(IList<DataPoint> newDataPoints, IList<DataPoint> 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);
}
}
}
/// <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)
{
dataPoint.SetBinding(DataPoint.StyleProperty, new Binding(ActualDataPointStyleName) { Source = this });
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>
/// Handles the SeriesHost's ResourceDictionariesChanged event.
/// </summary>
/// <param name="sender">ISeriesHost instance.</param>
/// <param name="e">Event args.</param>
private void SeriesHostResourceDictionariesChanged(object sender, EventArgs e)
{
DispensedResourcesChanging();
}
/// <summary>
/// Processes the change of the DispensedResources property.
/// </summary>
private void DispensedResourcesChanging()
{
if (null != PaletteResources)
{
Resources.MergedDictionaries.Remove(PaletteResources);
PaletteResources = null;
}
using (IEnumerator<ResourceDictionary> 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();
}
}
}