// (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.Globalization; using System.Windows.Data; namespace System.Windows.Controls.DataVisualization { /// /// Abstract base class for Interpolator converters. /// /// /// /// An Interpolator is used to project a value from a source range /// [ActualDataMinimum, ActualDataMaximum] to a target range [From, To]. /// The source range can be specified directly by setting the DataMinimum /// and/or DataMaximum properties, or indirectly by setting DataRangeBinding. /// When the DataRangeBinding property is set,the TreeMap will evaluate the /// binding for the entire tree, calculating the minimum and maximum values /// automatically. The custom target range and the actual interpolation /// logic is defined by sub-classes of this abstract class. /// /// /// Preview public abstract class Interpolator : FrameworkElement { /// /// Holds a helper object used to extract values using a property path. /// private BindingExtractor _helper; /// /// Gets or sets a value telling to which tree nodes the interpolation /// should be applied to. LeafNodesOnly by default. /// public InterpolationMode InterpolationMode { get; set; } /// /// Gets or sets a value representing the x:Name of the element to which /// the interpolated value will be applied. /// public string TargetName { get; set; } /// /// Gets or sets a value representing the path to a property which will /// receive the interpolated value. /// public string TargetProperty { get; set; } #region public double DataMinimum /// /// Gets or sets a value representing the fixed minimum value across the /// entire set. If the value is not set directly or is NaN, the /// ActualDataMaximum will be calculated automatically from the data set /// by using the DataRangeBinding property. /// public double DataMinimum { get { return (double)GetValue(DataMinimumProperty); } set { SetValue(DataMinimumProperty, value); } } /// /// Identifies the DataMinimum dependency property. /// public static readonly DependencyProperty DataMinimumProperty = DependencyProperty.Register( "DataMinimum", typeof(double), typeof(Interpolator), new PropertyMetadata(double.NaN)); #endregion public double DataMinimum #region public double DataMaximum /// /// Gets or sets a value representing the fixed maximum value across the /// entire set. If the value is not set directly or is NaN, the /// ActualDataMinimum will be calculated automatically from the data set /// by using the DataRangeBinding property. /// public double DataMaximum { get { return (double)GetValue(DataMaximumProperty); } set { SetValue(DataMaximumProperty, value); } } /// /// Identifies the DataMaximum dependency property. /// public static readonly DependencyProperty DataMaximumProperty = DependencyProperty.Register( "DataMaximum", typeof(double), typeof(Interpolator), new PropertyMetadata(double.NaN)); #endregion public double DataMaximum /// /// This fields contains the automatically calculated maximal value in /// the dataset. /// private double _actualDataMaximum; /// /// Gets the value representing the maximal value in the data set. It is /// automatically from the data set by using the DataRangeBinding /// property if DataMaximum is not set. If it is set, DataMaximum is /// returned. /// public double ActualDataMaximum { get { if (Double.IsNaN(DataMaximum)) { return _actualDataMaximum; } else { return DataMaximum; } } internal set { _actualDataMaximum = value; } } /// /// This fields contains the automatically calculated minimal value in /// the dataset. /// private double _actualDataMinimum; /// /// Gets the value representing the minimal value in the data set. It is /// automatically from the data set by using the DataRangeBinding /// property if DataMinimum is not set. If it is set, DataMinimum is /// returned. /// public double ActualDataMinimum { get { if (Double.IsNaN(DataMinimum)) { return _actualDataMinimum; } else { return DataMinimum; } } internal set { _actualDataMinimum = value; } } /// /// Gets or sets a binding to a property which will be examined to retrieve the minimum and maximum range /// values across the entire data set. If this value is null then the DataMinimum and DataMaximum values /// need be set manually. /// public Binding DataRangeBinding { get; set; } /// /// Initializes a new instance of the Interpolator class. /// protected Interpolator() { InterpolationMode = InterpolationMode.LeafNodesOnly; ActualDataMinimum = double.PositiveInfinity; ActualDataMaximum = double.NegativeInfinity; _helper = new BindingExtractor(); } /// /// If the DataRangeBinding property is set then this method updates the minimum/maximum range /// of this object by including the value passed in. /// /// Object to extract the value from (the Source of the DataRangeBinding). internal virtual void IncludeInRange(object data) { if (DataRangeBinding != null) { if (!Double.IsNaN(DataMinimum) && !Double.IsNaN(DataMaximum)) { return; } IConvertible input = _helper.RetrieveProperty(data, DataRangeBinding) as IConvertible; if (input == null) { throw new ArgumentException( Properties.Resources.Interpolator_IncludeInRange_DataRangeBindingNotIConvertible); } double value = input.ToDouble(CultureInfo.InvariantCulture); if (Double.IsNaN(DataMinimum) && value < ActualDataMinimum) { ActualDataMinimum = value; } if (Double.IsNaN(DataMaximum) && value > ActualDataMaximum) { ActualDataMaximum = value; } } } /// /// Called to interpolate the value of the given object between the DataMinimum and DataMaximum /// extremes, and to project it in a specific [From, To] range defined. The target range (and /// therefore the implementation of this method) is defined in a specific sub-class. /// /// Value to interpolate. /// An interpolated value. public abstract object Interpolate(double value); } }