// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) 2014 OxyPlot contributors
//
//
// Abstract base class for series.
//
// --------------------------------------------------------------------------------------------------------------------
using Avalonia;
using Avalonia.Utilities;
namespace OxyPlot.Avalonia
{
using global::Avalonia.Controls;
using global::Avalonia.Media;
using global::Avalonia.Utilities;
using System;
using System.Collections;
using System.Collections.Specialized;
///
/// Abstract base class for series.
///
public abstract class Series : ItemsControl
{
///
/// Identifies the dependency property.
///
public static readonly StyledProperty ColorProperty = AvaloniaProperty.Register(nameof(Color), MoreColors.Automatic);
///
/// Identifies the dependency property.
///
public static readonly StyledProperty TitleProperty = AvaloniaProperty.Register(nameof(Title), null);
///
/// Identifies the dependency property.
///
public static readonly StyledProperty RenderInLegendProperty = AvaloniaProperty.Register(nameof(RenderInLegend), true);
///
/// Identifies the dependency property.
///
public static readonly StyledProperty TrackerFormatStringProperty = AvaloniaProperty.Register(nameof(TrackerFormatString), null);
///
/// Identifies the dependency property.
///
public static readonly StyledProperty TrackerKeyProperty = AvaloniaProperty.Register(nameof(TrackerKey), null);
///
/// Identifies the dependency property.
///
public static readonly StyledProperty EdgeRenderingModeProperty = AvaloniaProperty.Register(nameof(EdgeRenderingMode), EdgeRenderingMode.Automatic);
///
/// The event listener used to subscribe to ItemSource.CollectionChanged events
///
private readonly EventListener eventListener;
///
/// Initializes static members of the class.
///
static Series()
{
IsVisibleProperty.Changed.AddClassHandler(AppearanceChanged);
BackgroundProperty.Changed.AddClassHandler(AppearanceChanged);
ColorProperty.Changed.AddClassHandler(AppearanceChanged);
TitleProperty.Changed.AddClassHandler(AppearanceChanged);
RenderInLegendProperty.Changed.AddClassHandler(AppearanceChanged);
TrackerFormatStringProperty.Changed.AddClassHandler(AppearanceChanged);
TrackerKeyProperty.Changed.AddClassHandler(AppearanceChanged);
EdgeRenderingModeProperty.Changed.AddClassHandler(AppearanceChanged);
}
///
/// Initializes a new instance of the class.
///
protected Series()
{
eventListener = new EventListener(OnCollectionChanged);
// Set Items to null for consistency with WPF behaviour in Oxyplot-Contrib
// Works around issue with BarSeriesManager throwing on empty Items collection in OxyPlot.Core 2.1
ItemsSource = null;
ItemsView.CollectionChanged += ItemsViewOnCollectionChanged;
}
///
/// Gets or sets Color.
///
public Color Color
{
get
{
return GetValue(ColorProperty);
}
set
{
SetValue(ColorProperty, value);
}
}
///
/// Gets or sets the internal series.
///
public OxyPlot.Series.Series InternalSeries { get; protected set; }
///
/// Gets or sets Title.
///
public string Title
{
get
{
return GetValue(TitleProperty);
}
set
{
SetValue(TitleProperty, value);
}
}
///
/// Gets or sets a value indicating whether the series should be rendered in the legend.
///
public bool RenderInLegend
{
get
{
return GetValue(RenderInLegendProperty);
}
set
{
SetValue(RenderInLegendProperty, value);
}
}
///
/// Gets or sets TrackerFormatString.
///
public string TrackerFormatString
{
get
{
return GetValue(TrackerFormatStringProperty);
}
set
{
SetValue(TrackerFormatStringProperty, value);
}
}
///
/// Gets or sets TrackerKey.
///
public string TrackerKey
{
get
{
return GetValue(TrackerKeyProperty);
}
set
{
SetValue(TrackerKeyProperty, value);
}
}
///
/// Gets or sets the for the series.
///
public EdgeRenderingMode EdgeRenderingMode
{
get
{
return GetValue(EdgeRenderingModeProperty);
}
set
{
SetValue(EdgeRenderingModeProperty, value);
}
}
///
/// Creates the model.
///
/// A series.
public abstract OxyPlot.Series.Series CreateModel();
///
/// The appearance changed.
///
/// The d.
/// The e.
protected static void AppearanceChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
((Series)d).OnVisualChanged();
}
///
/// The on visual changed handler.
///
protected void OnVisualChanged()
{
(this.Parent as IPlot)?.ElementAppearanceChanged(this);
}
///
/// The data changed.
///
/// The d.
/// The e.
protected static void DataChanged(AvaloniaObject d, AvaloniaPropertyChangedEventArgs e)
{
((Series)d).OnDataChanged();
}
///
/// The on data changed handler.
///
protected void OnDataChanged()
{
(this.Parent as IPlot)?.ElementDataChanged(this);
}
private void ItemsViewOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
SubscribeToCollectionChanged(e.OldItems, e.NewItems);
OnDataChanged();
}
protected override void OnAttachedToLogicalTree(global::Avalonia.LogicalTree.LogicalTreeAttachmentEventArgs e)
{
base.OnAttachedToLogicalTree(e);
//BeginInit();
//EndInit();
}
///
/// Synchronizes the properties.
///
/// The series.
protected virtual void SynchronizeProperties(OxyPlot.Series.Series s)
{
s.Background = Background.ToOxyColor();
s.Title = Title;
s.RenderInLegend = RenderInLegend;
s.TrackerFormatString = TrackerFormatString;
s.TrackerKey = TrackerKey;
s.TrackerFormatString = TrackerFormatString;
s.IsVisible = IsVisible;
s.Font = FontFamily.ToString();
s.TextColor = Foreground.ToOxyColor();
s.EdgeRenderingMode = EdgeRenderingMode;
}
///
/// If the ItemsSource implements INotifyCollectionChanged update the visual when the collection changes.
///
/// The old ItemsSource
/// The new ItemsSource
private void SubscribeToCollectionChanged(IEnumerable oldValue, IEnumerable newValue)
{
if (oldValue is INotifyCollectionChanged collection)
{
WeakEvents.CollectionChanged.Unsubscribe(collection, eventListener);
}
collection = newValue as INotifyCollectionChanged;
if (collection != null)
{
WeakEvents.CollectionChanged.Subscribe(collection, eventListener);
}
}
///
/// Invalidate the view when the collection changes
///
/// The sender
/// The collection changed args
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
OnDataChanged();
}
///
/// Listens to and forwards any collection changed events
///
private class EventListener : IWeakEventSubscriber
{
///
/// The delegate to forward to
///
private readonly EventHandler onCollectionChanged;
///
/// Initializes a new instance of the class
///
/// The handler
public EventListener(EventHandler onCollectionChanged)
{
this.onCollectionChanged = onCollectionChanged;
}
public void OnEvent(object sender, WeakEvent ev, NotifyCollectionChangedEventArgs e)
{
onCollectionChanged(sender, e);
}
}
}
}