Initial Commit
This commit is contained in:
54
Charts/Markers/BarChart.cs
Normal file
54
Charts/Markers/BarChart.cs
Normal file
@@ -0,0 +1,54 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Charts.Markers
|
||||
{
|
||||
public class OldBarChart : MarkerChart
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BarChart"/> class.
|
||||
/// </summary>
|
||||
public OldBarChart() { }
|
||||
|
||||
protected override void OnDataSourceChanged()
|
||||
{
|
||||
}
|
||||
|
||||
BarFromValueConverter converter = new BarFromValueConverter();
|
||||
List<double> xValues = new List<double>();
|
||||
protected override void OnMarkerBind(BindMarkerEventArgs e)
|
||||
{
|
||||
var marker = e.Marker;
|
||||
|
||||
//marker.SetBinding(ViewportRectPanel.ViewportVerticalAlignmentProperty, new Binding { Path = new PropertyPath("Value"), Converter = converter });
|
||||
|
||||
xValues.Add(ViewportPanel.GetX(marker));
|
||||
}
|
||||
|
||||
protected override void RebuildMarkers(bool shouldReleaseMarkers)
|
||||
{
|
||||
xValues.Clear();
|
||||
|
||||
base.RebuildMarkers(shouldReleaseMarkers);
|
||||
|
||||
double width = 0;
|
||||
for (int i = 0; i < xValues.Count - 1; i++)
|
||||
{
|
||||
double currX = xValues[i];
|
||||
double nextX = xValues[i + 1];
|
||||
width = (nextX - currX);
|
||||
|
||||
ViewportPanel.SetViewportWidth(ItemsPanel.Children[i], width);
|
||||
}
|
||||
|
||||
if (ItemsPanel.Children.Count > 0)
|
||||
{
|
||||
ViewportPanel.SetViewportWidth(ItemsPanel.Children[ItemsPanel.Children.Count - 1], width);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Charts/Markers/BarFromValueConverter.cs
Normal file
57
Charts/Markers/BarFromValueConverter.cs
Normal file
@@ -0,0 +1,57 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows.Data;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Charts.Markers
|
||||
{
|
||||
public class BarFromValueConverter : IValueConverter
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="BarFromValueConverter"/> class.
|
||||
/// </summary>
|
||||
public BarFromValueConverter() { }
|
||||
|
||||
public Brush PositiveBrush { get; set; }
|
||||
public Brush NegativeBrush { get; set; }
|
||||
|
||||
#region IValueConverter Members
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (!(value is double))
|
||||
return DependencyProperty.UnsetValue;
|
||||
|
||||
double height = (double)value;
|
||||
|
||||
if (targetType == typeof(Brush))
|
||||
{
|
||||
if (height > 0)
|
||||
return PositiveBrush;
|
||||
else
|
||||
return NegativeBrush;
|
||||
}
|
||||
else if (targetType == typeof(double))
|
||||
{
|
||||
return Math.Abs(height);
|
||||
}
|
||||
else if (targetType == typeof(VerticalAlignment))
|
||||
{
|
||||
return height > 0 ? VerticalAlignment.Bottom : VerticalAlignment.Top;
|
||||
}
|
||||
|
||||
return DependencyProperty.UnsetValue;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
16
Charts/Markers/BindMarkerInfo.cs
Normal file
16
Charts/Markers/BindMarkerInfo.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Charts.Markers
|
||||
{
|
||||
public sealed class BindMarkerEventArgs
|
||||
{
|
||||
internal BindMarkerEventArgs() { }
|
||||
|
||||
public FrameworkElement Marker { get; internal set; }
|
||||
public object Data { get; internal set; }
|
||||
}
|
||||
}
|
||||
286
Charts/Markers/MarkerChart.cs
Normal file
286
Charts/Markers/MarkerChart.cs
Normal file
@@ -0,0 +1,286 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Collections.Specialized;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.ComponentModel;
|
||||
using System.Diagnostics;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Charts.Markers
|
||||
{
|
||||
public class MarkerChart : PlotterElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="MarkerChart"/> class.
|
||||
/// </summary>
|
||||
public MarkerChart()
|
||||
{
|
||||
Viewport2D.SetIsContentBoundsHost(this, true);
|
||||
}
|
||||
|
||||
#region DataSource
|
||||
|
||||
private IEnumerable dataSource;
|
||||
/// <summary>
|
||||
/// Gets or sets the data source.
|
||||
/// Value can be null.
|
||||
/// </summary>
|
||||
/// <value>The data source.</value>
|
||||
public IEnumerable DataSource
|
||||
{
|
||||
get { return dataSource; }
|
||||
set
|
||||
{
|
||||
DetachDataSource();
|
||||
dataSource = value;
|
||||
AttachDataSource();
|
||||
|
||||
OnDataSourceChanged();
|
||||
|
||||
RebuildMarkers(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDataSourceChanged() { }
|
||||
|
||||
protected virtual void RebuildMarkers(bool shouldReleaseMarkers)
|
||||
{
|
||||
if (markerGenerator == null)
|
||||
return;
|
||||
|
||||
if (shouldReleaseMarkers)
|
||||
{
|
||||
foreach (FrameworkElement item in itemsPanel.Children)
|
||||
{
|
||||
var enumerator = item.GetLocalValueEnumerator();
|
||||
while (enumerator.MoveNext())
|
||||
{
|
||||
item.ClearValue(enumerator.Current.Property);
|
||||
}
|
||||
|
||||
descriptor.RemoveValueChanged(item, OnMarkerViewportBoundsChanged);
|
||||
markerGenerator.ReleaseMarker(item);
|
||||
}
|
||||
}
|
||||
|
||||
itemsPanel.Children.Clear();
|
||||
|
||||
if (dataSource == null)
|
||||
return;
|
||||
|
||||
IndividualArrangePanel specialPanel = itemsPanel as IndividualArrangePanel;
|
||||
if (specialPanel != null)
|
||||
specialPanel.BeginBatchAdd();
|
||||
|
||||
foreach (object item in dataSource)
|
||||
{
|
||||
var marker = CreateMarker(item);
|
||||
itemsPanel.Children.Add(marker);
|
||||
}
|
||||
|
||||
if (specialPanel != null)
|
||||
specialPanel.EndBatchAdd();
|
||||
|
||||
RecalculateViewportBounds();
|
||||
}
|
||||
|
||||
private FrameworkElement CreateMarker(object item)
|
||||
{
|
||||
var marker = markerGenerator.CreateMarker(item);
|
||||
if (marker != null)
|
||||
{
|
||||
marker.DataContext = item;
|
||||
AttachViewportChangedListener(marker);
|
||||
|
||||
BindMarkerEventArgs bindArgs = new BindMarkerEventArgs { Data = item, Marker = marker };
|
||||
|
||||
OnMarkerBind(bindArgs);
|
||||
|
||||
if (markerBindCallback != null)
|
||||
{
|
||||
markerBindCallback(bindArgs);
|
||||
}
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
protected virtual void OnMarkerBind(BindMarkerEventArgs e) { }
|
||||
|
||||
private Action<BindMarkerEventArgs> markerBindCallback = null;
|
||||
public Action<BindMarkerEventArgs> MarkerBindCallback
|
||||
{
|
||||
get { return markerBindCallback; }
|
||||
set
|
||||
{
|
||||
if (markerBindCallback != value)
|
||||
{
|
||||
markerBindCallback = value;
|
||||
RebuildMarkers(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachDataSource()
|
||||
{
|
||||
INotifyCollectionChanged notifyingCollection = dataSource as INotifyCollectionChanged;
|
||||
if (notifyingCollection != null)
|
||||
{
|
||||
notifyingCollection.CollectionChanged += OnDataSourceCollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataSourceCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
if (e.OldItems != null)
|
||||
{
|
||||
int index = e.OldStartingIndex;
|
||||
foreach (object item in e.OldItems)
|
||||
{
|
||||
var oldMarker = itemsPanel.Children[index];
|
||||
|
||||
if (markerGenerator != null)
|
||||
{
|
||||
FrameworkElement element = (FrameworkElement)oldMarker;
|
||||
// todo call cleanup callback here
|
||||
markerGenerator.ReleaseMarker(element);
|
||||
descriptor.RemoveValueChanged(element, OnMarkerViewportBoundsChanged);
|
||||
}
|
||||
|
||||
itemsPanel.Children.RemoveAt(index);
|
||||
}
|
||||
}
|
||||
|
||||
if (e.NewItems != null)
|
||||
{
|
||||
int index = e.NewStartingIndex;
|
||||
foreach (object item in e.NewItems)
|
||||
{
|
||||
var marker = CreateMarker(item);
|
||||
itemsPanel.Children.Insert(index, marker);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
RecalculateViewportBounds();
|
||||
}
|
||||
|
||||
DependencyPropertyDescriptor descriptor = DependencyPropertyDescriptor.FromProperty(ViewportPanel.ActualViewportBoundsProperty, typeof(FrameworkElement));
|
||||
|
||||
private void AttachViewportChangedListener(FrameworkElement element)
|
||||
{
|
||||
// todo or use this, or remove this
|
||||
|
||||
//descriptor.RemoveValueChanged(element, OnMarkerViewportBoundsChanged);
|
||||
//descriptor.AddValueChanged(element, OnMarkerViewportBoundsChanged);
|
||||
}
|
||||
|
||||
private Rect viewportBounds = Rect.Empty;
|
||||
|
||||
private void OnMarkerViewportBoundsChanged(object sender, EventArgs e)
|
||||
{
|
||||
RecalculateViewportBounds();
|
||||
FrameworkElement element = (FrameworkElement)sender;
|
||||
DataRect elementBounds = ViewportPanel.GetActualViewportBounds(element);
|
||||
DataRect prevElementBounds = ViewportPanel.GetPrevActualViewportBounds(element);
|
||||
}
|
||||
|
||||
private void RecalculateViewportBounds()
|
||||
{
|
||||
DataRect bounds = DataRect.Empty;
|
||||
|
||||
foreach (UIElement item in itemsPanel.Children)
|
||||
{
|
||||
DataRect elementBounds = ViewportPanel.GetActualViewportBounds(item);
|
||||
bounds.Union(elementBounds);
|
||||
}
|
||||
|
||||
Viewport2D.SetContentBounds(this, bounds);
|
||||
}
|
||||
|
||||
private void DetachDataSource()
|
||||
{
|
||||
INotifyCollectionChanged notifyingCollection = dataSource as INotifyCollectionChanged;
|
||||
if (notifyingCollection != null)
|
||||
{
|
||||
notifyingCollection.CollectionChanged -= OnDataSourceCollectionChanged;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Marker
|
||||
|
||||
private OldMarkerGenerator markerGenerator;
|
||||
public OldMarkerGenerator MarkerGenerator
|
||||
{
|
||||
get { return markerGenerator; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (markerGenerator != value)
|
||||
{
|
||||
DetachMarkerGenerator();
|
||||
markerGenerator = value;
|
||||
AttachMarkerGenerator();
|
||||
|
||||
RebuildMarkers(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void AttachMarkerGenerator()
|
||||
{
|
||||
markerGenerator.Changed += OnMarkerChanged;
|
||||
}
|
||||
|
||||
private void OnMarkerChanged(object sender, EventArgs e)
|
||||
{
|
||||
RebuildMarkers(false);
|
||||
}
|
||||
|
||||
private void DetachMarkerGenerator()
|
||||
{
|
||||
if (markerGenerator != null)
|
||||
{
|
||||
markerGenerator.Changed -= OnMarkerChanged;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Plotter attaching
|
||||
|
||||
private ViewportPanel itemsPanel = new ViewportPanel();
|
||||
protected Panel ItemsPanel
|
||||
{
|
||||
get { return itemsPanel; }
|
||||
}
|
||||
|
||||
private Plotter2D plotter;
|
||||
protected override void OnPlotterAttached(Plotter plotter)
|
||||
{
|
||||
base.OnPlotterAttached(plotter);
|
||||
|
||||
this.plotter = (Plotter2D)plotter;
|
||||
((IPlotterElement)itemsPanel).OnPlotterAttached(plotter);
|
||||
}
|
||||
|
||||
protected override void OnPlotterDetaching(Plotter plotter)
|
||||
{
|
||||
((IPlotterElement)itemsPanel).OnPlotterDetaching(plotter);
|
||||
|
||||
this.plotter = null;
|
||||
|
||||
base.OnPlotterDetaching(plotter);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
26
Charts/Markers/OldMarkerGenerator.cs
Normal file
26
Charts/Markers/OldMarkerGenerator.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Charts.Markers
|
||||
{
|
||||
public abstract class OldMarkerGenerator : DependencyObject
|
||||
{
|
||||
public FrameworkElement CreateMarker(object dataItem)
|
||||
{
|
||||
return CreateMarkerCore(dataItem);
|
||||
}
|
||||
|
||||
protected abstract FrameworkElement CreateMarkerCore(object dataItem);
|
||||
|
||||
protected void RaiseChanged()
|
||||
{
|
||||
Changed.Raise(this);
|
||||
}
|
||||
public event EventHandler Changed;
|
||||
|
||||
public virtual void ReleaseMarker(FrameworkElement element) { }
|
||||
}
|
||||
}
|
||||
55
Charts/Markers/TemplateMarkerGenerator2.cs
Normal file
55
Charts/Markers/TemplateMarkerGenerator2.cs
Normal file
@@ -0,0 +1,55 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using Microsoft.Research.DynamicDataDisplay.Common;
|
||||
using System.Windows.Markup;
|
||||
using System.Windows.Controls;
|
||||
|
||||
namespace Microsoft.Research.DynamicDataDisplay.Charts.Markers
|
||||
{
|
||||
[ContentProperty("Template")]
|
||||
public class TemplateMarkerGenerator2 : OldMarkerGenerator
|
||||
{
|
||||
private DataTemplate template;
|
||||
[NotNull]
|
||||
public DataTemplate Template
|
||||
{
|
||||
get { return template; }
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
throw new ArgumentNullException("value");
|
||||
|
||||
if (template != value)
|
||||
{
|
||||
template = value;
|
||||
pool.Clear();
|
||||
RaiseChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private readonly ResourcePool<FrameworkElement> pool = new ResourcePool<FrameworkElement>();
|
||||
|
||||
protected override FrameworkElement CreateMarkerCore(object dataItem)
|
||||
{
|
||||
if (template == null)
|
||||
throw new InvalidOperationException(Strings.Exceptions.TemplateShouldNotBeNull);
|
||||
|
||||
FrameworkElement marker = pool.Get();
|
||||
if (marker == null)
|
||||
{
|
||||
marker = (FrameworkElement)template.LoadContent();
|
||||
}
|
||||
|
||||
return marker;
|
||||
}
|
||||
|
||||
public override void ReleaseMarker(FrameworkElement element)
|
||||
{
|
||||
pool.Put(element);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user