using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media.Effects;
using System;
namespace Microsoft.Research.DynamicDataDisplay
{
///
/// Legend - shows list of annotations to charts.
///
public partial class Legend : ContentControl, IPlotterElement
{
///
/// Initializes a new instance of the class.
///
public Legend()
{
InitializeComponent();
#if !RELEASEXBAP
shadowRect.Effect = new DropShadowEffect { Direction = 300, ShadowDepth = 3, Opacity = 0.4 };
#endif
}
#region Position properties
public double LegendLeft
{
get { return (double)GetValue(LegendLeftProperty); }
set { SetValue(LegendLeftProperty, value); }
}
public static readonly DependencyProperty LegendLeftProperty = DependencyProperty.Register(
"LegendLeft",
typeof(double),
typeof(Legend),
new FrameworkPropertyMetadata(Double.NaN));
public double LegendRight
{
get { return (double)GetValue(LegendRightProperty); }
set { SetValue(LegendRightProperty, value); }
}
public static readonly DependencyProperty LegendRightProperty = DependencyProperty.Register(
"LegendRight",
typeof(double),
typeof(Legend),
new FrameworkPropertyMetadata(10.0));
public double LegendBottom
{
get { return (double)GetValue(LegendBottomProperty); }
set { SetValue(LegendBottomProperty, value); }
}
public static readonly DependencyProperty LegendBottomProperty = DependencyProperty.Register(
"LegendBottom",
typeof(double),
typeof(Legend),
new FrameworkPropertyMetadata(Double.NaN));
public double LegendTop
{
get { return (double)GetValue(LegendTopProperty); }
set { SetValue(LegendTopProperty, value); }
}
public static readonly DependencyProperty LegendTopProperty = DependencyProperty.Register(
"LegendTop",
typeof(double),
typeof(Legend),
new FrameworkPropertyMetadata(10.0));
#endregion
public override bool ShouldSerializeContent()
{
return false;
}
#region Plotter attached & detached
private Plotter plotter;
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public Plotter Plotter
{
get { return plotter; }
}
void IPlotterElement.OnPlotterAttached(Plotter plotter)
{
this.plotter = plotter;
plotter.Children.CollectionChanged += OnPlotterChildrenChanged;
plotter.CentralGrid.Children.Add(this);
SubscribeOnEvents();
PopulateLegend();
}
private void SubscribeOnEvents()
{
foreach (var item in plotter.Children.OfType())
{
item.PropertyChanged += OnChartPropertyChanged;
}
}
private void OnPlotterChildrenChanged(object sender, NotifyCollectionChangedEventArgs e)
{
ManageEvents(e);
PopulateLegend();
}
private void ManageEvents(NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
{
foreach (var item in e.OldItems.OfType())
{
item.PropertyChanged -= OnChartPropertyChanged;
}
}
if (e.NewItems != null)
{
foreach (var item in e.NewItems.OfType())
{
item.PropertyChanged += OnChartPropertyChanged;
}
}
}
private void OnChartPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Description")
{
ViewportElement2D chart = sender as ViewportElement2D;
if (chart != null && cachedLegendItems.ContainsKey(chart))
{
// todo dirty, but quick to code.
PopulateLegend();
}
}
}
void IPlotterElement.OnPlotterDetaching(Plotter plotter)
{
UnsubscribeFromEvents();
plotter.CentralGrid.Children.Remove(this);
plotter.Children.CollectionChanged -= OnPlotterChildrenChanged;
this.plotter = null;
PopulateLegend();
}
private void UnsubscribeFromEvents()
{
foreach (var item in plotter.Children.OfType())
{
item.PropertyChanged -= OnChartPropertyChanged;
}
}
#endregion
public Grid ContentGrid
{
get { return grid; }
}
public Panel ContentPanel
{
get { return stackPanel; }
}
private bool autoShowAndHide = true;
///
/// Gets or sets a value indicating whether legend automatically shows or hides itself
/// when chart collection changes.
///
/// true if legend automatically shows and hides itself when chart collection changes; otherwise, false.
public bool AutoShowAndHide
{
get { return autoShowAndHide; }
set { autoShowAndHide = value; }
}
///
/// Adds new legend item.
///
/// The legend item.
public void AddLegendItem(LegendItem legendItem)
{
stackPanel.Children.Add(legendItem);
UpdateVisibility();
}
///
/// Removes the legend item.
///
/// The legend item.
public void RemoveLegendItem(LegendItem legendItem)
{
stackPanel.Children.Remove(legendItem);
UpdateVisibility();
}
private void UpdateVisibility()
{
if (stackPanel.Children.Count > 0 && ReadLocalValue(VisibilityProperty) == DependencyProperty.UnsetValue && autoShowAndHide == true)
{
Visibility = Visibility.Visible;
}
else if (stackPanel.Children.Count == 0 && ReadLocalValue(VisibilityProperty) != DependencyProperty.UnsetValue && autoShowAndHide == true)
{
Visibility = Visibility.Hidden;
}
}
private readonly Dictionary cachedLegendItems = new Dictionary();
private void ParentChartPlotter_CollectionChanged(object sender, CollectionChangeEventArgs e)
{
stackPanel.Children.Clear();
PopulateLegend();
}
private void graph_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Description")
{
ViewportElement2D graph = (ViewportElement2D)sender;
LegendItem oldLegendItem = cachedLegendItems[graph];
int index = stackPanel.Children.IndexOf(oldLegendItem);
stackPanel.Children.RemoveAt(index);
LegendItem newLegendItem = graph.Description.LegendItem;
cachedLegendItems[graph] = newLegendItem;
stackPanel.Children.Insert(index, newLegendItem);
}
}
public void PopulateLegend()
{
stackPanel.Children.Clear();
if (plotter == null)
{
return;
}
cachedLegendItems.Clear();
foreach (var graph in plotter.Children.OfType())
{
if (GetVisibleInLegend(graph))
{
LegendItem legendItem = graph.Description.LegendItem;
cachedLegendItems.Add(graph, legendItem);
AddLegendItem(legendItem);
}
}
UpdateVisibility();
}
#region VisibleInLegend attached dependency property
public static bool GetVisibleInLegend(DependencyObject obj)
{
return (bool)obj.GetValue(VisibleInLegendProperty);
}
public static void SetVisibleInLegend(DependencyObject obj, bool value)
{
obj.SetValue(VisibleInLegendProperty, value);
}
public static readonly DependencyProperty VisibleInLegendProperty =
DependencyProperty.RegisterAttached(
"VisibleInLegend",
typeof(bool),
typeof(Legend), new FrameworkPropertyMetadata(false, OnVisibleInLegendChanged));
private static void OnVisibleInLegendChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartPlotter plotter = Plotter.GetPlotter(d) as ChartPlotter;
if (plotter != null)
{
plotter.Legend.PopulateLegend();
}
}
#endregion
}
}