Files
DynamicDataDisplay/Charts/Axes/LabelProviderBase.cs
2024-02-23 00:46:06 -05:00

213 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
using Microsoft.Research.DynamicDataDisplay.Common;
using System.ComponentModel;
namespace Microsoft.Research.DynamicDataDisplay.Charts.Axes
{
/// <summary>
/// Contains data for custom generation of tick's label.
/// </summary>
/// <typeparam name="T">Type of ticks</typeparam>
public sealed class LabelTickInfo<T>
{
internal LabelTickInfo() { }
/// <summary>
/// Gets or sets the tick.
/// </summary>
/// <value>The tick.</value>
public T Tick { get; internal set; }
/// <summary>
/// Gets or sets additional info about ticks range.
/// </summary>
/// <value>The info.</value>
public object Info { get; internal set; }
/// <summary>
/// Gets or sets the index of tick in ticks array.
/// </summary>
/// <value>The index.</value>
public int Index { get; internal set; }
}
/// <summary>
/// Base class for all label providers.
/// Contains a number of properties that can be used to adjust generated labels.
/// </summary>
/// <typeparam name="T">Type of ticks, which labels are generated for</typeparam>
/// <remarks>
/// Order of apllication of custom label string properties:
/// If CustomFormatter is not null, it is called first.
/// Then, if it was null or if it returned null string,
/// virtual GetStringCore method is called. It can be overloaded in subclasses. GetStringCore should not return null.
/// Then if LabelStringFormat is not null, it is applied.
/// After label's UI was created, you can change it by setting CustomView delegate - it allows you to adjust
/// UI properties of label. Note: not all labelProviders takes CustomView into account.
/// </remarks>
public abstract class LabelProviderBase<T>
{
#region Private
private string labelStringFormat = null;
private Func<LabelTickInfo<T>, string> customFormatter = null;
private Action<LabelTickInfo<T>, UIElement> customView = null;
#endregion
private static readonly UIElement[] emptyLabelsArray = new UIElement[0];
protected static UIElement[] EmptyLabelsArray
{
get { return emptyLabelsArray; }
}
/// <summary>
/// Creates labels by given ticks info.
/// Is not intended to be called from your code.
/// </summary>
/// <param name="ticksInfo">The ticks info.</param>
/// <returns>Array of <see cref="UIElement"/>s, which are axis labels for specified axis ticks.</returns>
[EditorBrowsable(EditorBrowsableState.Never)]
public abstract UIElement[] CreateLabels(ITicksInfo<T> ticksInfo);
/// <summary>
/// Gets or sets the label string format.
/// </summary>
/// <value>The label string format.</value>
public string LabelStringFormat
{
get { return labelStringFormat; }
set
{
if (labelStringFormat != value)
{
labelStringFormat = value;
RaiseChanged();
}
}
}
/// <summary>
/// Gets or sets the custom formatter - delegate that can be called to create custom string representation of tick.
/// </summary>
/// <value>The custom formatter.</value>
public Func<LabelTickInfo<T>, string> CustomFormatter
{
get { return customFormatter; }
set
{
if (customFormatter != value)
{
customFormatter = value;
RaiseChanged();
}
}
}
/// <summary>
/// Gets or sets the custom view - delegate that is used to create a custom, non-default look of axis label.
/// Can be used to adjust some UI properties of generated label.
/// </summary>
/// <value>The custom view.</value>
public Action<LabelTickInfo<T>, UIElement> CustomView
{
get { return customView; }
set
{
if (customView != value)
{
customView = value;
RaiseChanged();
}
}
}
/// <summary>
/// Sets the custom formatter.
/// This is alternative to CustomFormatter property setter, the only difference is that Visual Studio shows
/// more convenient tooltip for methods rather than for properties' setters.
/// </summary>
/// <param name="formatter">The formatter.</param>
public void SetCustomFormatter(Func<LabelTickInfo<T>, string> formatter)
{
CustomFormatter = formatter;
}
/// <summary>
/// Sets the custom view.
/// This is alternative to CustomView property setter, the only difference is that Visual Studio shows
/// more convenient tooltip for methods rather than for properties' setters.
/// </summary>
/// <param name="view">The view.</param>
public void SetCustomView(Action<LabelTickInfo<T>, UIElement> view)
{
CustomView = view;
}
protected virtual string GetString(LabelTickInfo<T> tickInfo)
{
string text = null;
if (CustomFormatter != null)
{
text = CustomFormatter(tickInfo);
}
if (text == null)
{
text = GetStringCore(tickInfo);
if (text == null)
throw new ArgumentNullException(Strings.Exceptions.TextOfTickShouldNotBeNull);
}
if (LabelStringFormat != null)
{
text = String.Format(LabelStringFormat, text);
}
return text;
}
protected virtual string GetStringCore(LabelTickInfo<T> tickInfo)
{
return tickInfo.Tick.ToString();
}
protected void ApplyCustomView(LabelTickInfo<T> info, UIElement label)
{
if (CustomView != null)
{
CustomView(info, label);
}
}
/// <summary>
/// Occurs when label provider is changed.
/// Notifies axis to update its view.
/// </summary>
public event EventHandler Changed;
protected void RaiseChanged()
{
Changed.Raise(this);
}
private readonly ResourcePool<UIElement> pool = new ResourcePool<UIElement>();
internal void ReleaseLabel(UIElement label)
{
if (ReleaseCore(label))
{
pool.Put(label);
}
}
protected virtual bool ReleaseCore(UIElement label) { return false; }
protected UIElement GetResourceFromPool()
{
return pool.Get();
}
}
}