This commit is contained in:
2024-02-23 09:29:44 -05:00
parent 2bbedc0178
commit 0038248f33
398 changed files with 39074 additions and 0 deletions

View File

@@ -0,0 +1,102 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Collections;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>Data source that is a composer from several other data sources.</summary>
public class CompositeDataSource : IPointDataSource {
/// <summary>Initializes a new instance of the <see cref="CompositeDataSource"/> class</summary>
public CompositeDataSource() { }
/// <summary>
/// Initializes a new instance of the <see cref="CompositeDataSource"/> class.
/// </summary>
/// <param name="dataSources">Data sources.</param>
public CompositeDataSource(params IPointDataSource[] dataSources) {
if (dataSources == null)
throw new ArgumentNullException("dataSources");
foreach (var dataSource in dataSources) {
AddDataPart(dataSource);
}
}
private readonly List<IPointDataSource> dataParts = new List<IPointDataSource>();
public IEnumerable<IPointDataSource> DataParts {
get { return dataParts; }
}
/// <summary>
/// Adds data part.
/// </summary>
/// <param name="dataPart">The data part.</param>
public void AddDataPart(IPointDataSource dataPart) {
if (dataPart == null)
throw new ArgumentNullException("dataPart");
dataParts.Add(dataPart);
dataPart.DataChanged += OnPartDataChanged;
}
private void OnPartDataChanged(object sender, EventArgs e) {
RaiseDataChanged();
}
#region IPointSource Members
public event EventHandler DataChanged;
protected void RaiseDataChanged() {
if (DataChanged != null) {
DataChanged(this, EventArgs.Empty);
}
}
public IPointEnumerator GetEnumerator(DependencyObject context) {
return new CompositeEnumerator(this, context);
}
#endregion
private sealed class CompositeEnumerator : IPointEnumerator {
private readonly IEnumerable<IPointEnumerator> enumerators;
public CompositeEnumerator(CompositeDataSource dataSource, DependencyObject context) {
enumerators = dataSource.dataParts.Select(part => part.GetEnumerator(context)).ToList();
}
#region IChartPointEnumerator Members
public bool MoveNext() {
bool res = false;
foreach (var enumerator in enumerators) {
res |= enumerator.MoveNext();
}
return res;
}
public void ApplyMappings(DependencyObject glyph) {
foreach (var enumerator in enumerators) {
enumerator.ApplyMappings(glyph);
}
}
public void GetCurrent(ref Point p) {
foreach (var enumerator in enumerators) {
enumerator.GetCurrent(ref p);
}
}
public void Dispose() {
foreach (var enumerator in enumerators) {
enumerator.Dispose();
}
}
#endregion
}
}
}

View File

@@ -0,0 +1,92 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
public static class DataSourceExtensions
{
public static RawDataSource AsDataSource(this IEnumerable<Point> points)
{
return new RawDataSource(points);
}
public static EnumerableDataSource<T> AsDataSource<T>(this IEnumerable<T> collection)
{
return new EnumerableDataSource<T>(collection);
}
public static EnumerableDataSource<T> AsXDataSource<T>(this IEnumerable<T> collection)
{
if (typeof(T) == typeof(double))
{
return ((IEnumerable<double>)collection).AsXDataSource() as EnumerableDataSource<T>;
}
else if (typeof(T) == typeof(float))
{
return ((IEnumerable<float>)collection).AsXDataSource() as EnumerableDataSource<T>;
}
return new EnumerableXDataSource<T>(collection);
}
public static EnumerableDataSource<float> AsXDataSource(this IEnumerable<float> collection)
{
EnumerableXDataSource<float> ds = new EnumerableXDataSource<float>(collection);
ds.SetXMapping(f => (double)f);
return ds;
}
public static EnumerableDataSource<T> AsYDataSource<T>(this IEnumerable<T> collection)
{
if (typeof(T) == typeof(double))
{
return ((IEnumerable<double>)collection).AsYDataSource() as EnumerableDataSource<T>;
}
else if (typeof(T) == typeof(float))
{
return ((IEnumerable<float>)collection).AsYDataSource() as EnumerableDataSource<T>;
}
return new EnumerableYDataSource<T>(collection);
}
public static EnumerableDataSource<double> AsXDataSource(this IEnumerable<double> collection)
{
EnumerableXDataSource<double> ds = new EnumerableXDataSource<double>(collection);
ds.SetXMapping(x => x);
return ds;
}
public static EnumerableDataSource<double> AsYDataSource(this IEnumerable<double> collection)
{
EnumerableYDataSource<double> ds = new EnumerableYDataSource<double>(collection);
ds.SetYMapping(y => y);
return ds;
}
public static EnumerableDataSource<float> AsYDataSource(this IEnumerable<float> collection)
{
EnumerableYDataSource<float> ds = new EnumerableYDataSource<float>(collection);
ds.SetYMapping(f => (double)f);
return ds;
}
public static CompositeDataSource Join(this IPointDataSource ds1, IPointDataSource ds2)
{
return new CompositeDataSource(ds1, ds2);
}
public static IEnumerable<Point> GetPoints(this IPointDataSource dataSource)
{
return DataSourceHelper.GetPoints(dataSource);
}
public static IEnumerable<Point> GetPoints(this IPointDataSource dataSource, DependencyObject context)
{
return DataSourceHelper.GetPoints(dataSource, context);
}
}
}

View File

@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.Charts;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
public static class DataSourceHelper
{
public static IEnumerable<Point> GetPoints(IPointDataSource dataSource)
{
return GetPoints(dataSource, null);
}
public static IEnumerable<Point> GetPoints(IPointDataSource dataSource, DependencyObject context)
{
if (dataSource == null)
throw new ArgumentNullException("dataSource");
if (context == null)
context = new DataSource2dContext();
using (IPointEnumerator enumerator = dataSource.GetEnumerator(context))
{
Point p = new Point();
while (enumerator.MoveNext())
{
enumerator.GetCurrent(ref p);
yield return p;
p = new Point();
}
}
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Diagnostics.CodeAnalysis;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>
/// Empty data source - for testing purposes, represents data source with 0 points inside.
/// </summary>
public class EmptyDataSource : IPointDataSource
{
#region IPointDataSource Members
public IPointEnumerator GetEnumerator(DependencyObject context)
{
return new EmptyPointEnumerator();
}
[SuppressMessage("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
private void RaiseDataChanged()
{
if (DataChanged != null)
{
DataChanged(this, EventArgs.Empty);
}
}
public event EventHandler DataChanged;
#endregion
private sealed class EmptyPointEnumerator : IPointEnumerator
{
public bool MoveNext()
{
return false;
}
public void GetCurrent(ref Point p)
{
// nothing to do
}
public void ApplyMappings(DependencyObject target)
{
// nothing to do
}
public void Dispose() { }
}
}
}

View File

@@ -0,0 +1,109 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
public class EnumerableDataSource<T> : EnumerableDataSourceBase<T>
{
public EnumerableDataSource(IEnumerable<T> data) : base(data) { }
public EnumerableDataSource(IEnumerable data) : base(data) { }
private readonly List<Mapping<T>> mappings = new List<Mapping<T>>();
private Func<T, double> xMapping;
private Func<T, double> yMapping;
private Func<T, Point> xyMapping;
public Func<T, double> XMapping
{
get { return xMapping; }
set { SetXMapping(value); }
}
public Func<T, double> YMapping
{
get { return yMapping; }
set { SetYMapping(value); }
}
public Func<T, Point> XYMapping
{
get { return xyMapping; }
set { SetXYMapping(value); }
}
public void SetXMapping(Func<T, double> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.xMapping = mapping;
RaiseDataChanged();
}
public void SetYMapping(Func<T, double> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.yMapping = mapping;
RaiseDataChanged();
}
public void SetXYMapping(Func<T, Point> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.xyMapping = mapping;
RaiseDataChanged();
}
public void AddMapping(DependencyProperty property, Func<T, object> mapping)
{
if (property == null)
throw new ArgumentNullException("property");
if (mapping == null)
throw new ArgumentNullException("mapping");
mappings.Add(new Mapping<T> { Property = property, F = mapping });
}
public override IPointEnumerator GetEnumerator(DependencyObject context)
{
return new EnumerablePointEnumerator<T>(this);
}
internal void FillPoint(T elem, ref Point point)
{
if (xyMapping != null)
{
point = xyMapping(elem);
}
else
{
if (xMapping != null)
{
point.X = xMapping(elem);
}
if (yMapping != null)
{
point.Y = yMapping(elem);
}
}
}
internal void ApplyMappings(DependencyObject target, T elem)
{
if (target != null)
{
foreach (var mapping in mappings)
{
target.SetValue(mapping.Property, mapping.F(elem));
}
}
}
}
}

View File

@@ -0,0 +1,56 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>Base class for all sources who receive data for charting
/// from any IEnumerable of T</summary>
/// <typeparam name="T">Type of items in IEnumerable</typeparam>
public abstract class EnumerableDataSourceBase<T> : IPointDataSource {
private IEnumerable data;
/// <summary>
/// Gets or sets the data.
/// </summary>
/// <value>The data.</value>
public IEnumerable Data {
get { return data; }
set {
if (value == null)
throw new ArgumentNullException("value");
data = value;
var observableCollection = data as INotifyCollectionChanged;
if (observableCollection != null) {
observableCollection.CollectionChanged += observableCollection_CollectionChanged;
}
}
}
protected EnumerableDataSourceBase(IEnumerable<T> data) : this((IEnumerable)data) { }
protected EnumerableDataSourceBase(IEnumerable data) {
if (data == null)
throw new ArgumentNullException("data");
Data = data;
}
private void observableCollection_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
RaiseDataChanged();
}
public event EventHandler DataChanged;
public void RaiseDataChanged() {
if (DataChanged != null) {
DataChanged(this, EventArgs.Empty);
}
}
public abstract IPointEnumerator GetEnumerator(DependencyObject context);
}
}

View File

@@ -0,0 +1,33 @@
using System.Collections;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>This enumerator enumerates given enumerable object as sequence of points</summary>
/// <typeparam name="T">Type parameter of source IEnumerable</typeparam>
public sealed class EnumerablePointEnumerator<T> : IPointEnumerator {
private readonly EnumerableDataSource<T> dataSource;
private readonly IEnumerator enumerator;
public EnumerablePointEnumerator(EnumerableDataSource<T> dataSource) {
this.dataSource = dataSource;
enumerator = dataSource.Data.GetEnumerator();
}
public bool MoveNext() {
return enumerator.MoveNext();
}
public void GetCurrent(ref Point p) {
dataSource.FillPoint((T)enumerator.Current, ref p);
}
public void ApplyMappings(DependencyObject target) {
dataSource.ApplyMappings(target, (T)enumerator.Current);
}
public void Dispose() {
//enumerator.Reset();
}
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
internal sealed class EnumerableXDataSource<T> : EnumerableDataSource<T>
{
public EnumerableXDataSource(IEnumerable<T> data) : base(data) { }
}
}

View File

@@ -0,0 +1,12 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
internal sealed class EnumerableYDataSource<T> : EnumerableDataSource<T>
{
public EnumerableYDataSource(IEnumerable<T> data) : base(data) { }
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>Data source that returns sequence of 2D points.</summary>
public interface IPointDataSource
{
/// <summary>Returns object to enumerate points in source.</summary>
IPointEnumerator GetEnumerator(DependencyObject context);
/// <summary>This event is raised when contents of source are changed.</summary>
event EventHandler DataChanged;
}
}

View File

@@ -0,0 +1,21 @@
using System;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
public interface IPointEnumerator : IDisposable {
/// <summary>Move to next point in sequence</summary>
/// <returns>True if successfully moved to next point
/// or false if end of sequence is reached</returns>
bool MoveNext();
/// <summary>Stores current value(s) in given point.</summary>
/// <param name="p">Reference to store value</param>
/// <remarks>Depending on implementing class this method may set only X or Y
/// fields in specified point. That's why GetCurrent is a regular method and
/// not a property as in standard enumerators</remarks>
void GetCurrent(ref Point p);
void ApplyMappings(DependencyObject target);
}
}

View File

@@ -0,0 +1,15 @@
using System;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>Mapping class holds information about mapping of TSource type
/// to some DependencyProperty.</summary>
/// <typeparam name="TSource">Mapping source type.</typeparam>
internal sealed class Mapping<TSource> {
/// <summary>Property that will be set.</summary>
internal DependencyProperty Property { get; set; }
/// <summary>Function that computes value for property from TSource type.</summary>
internal Func<TSource, object> F { get; set; }
}
}

View File

@@ -0,0 +1,220 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Threading;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
// todo I don't think that we should create data source which supports
// suspending its DataChanged event - it is better to create
// collection with the same functionality - then it would be able to be used
// as a source in many data sources.
public class ObservableDataSource<T> : IPointDataSource
{
/// <summary>True if collection was changed between SuspendUpdate and ResumeUpdate
/// or false otherwise</summary>
private bool collectionChanged = false;
/// <summary>True if event should be raised on each collection change
/// or false otherwise</summary>
private bool updatesEnabled = true;
public ObservableDataSource()
{
collection.CollectionChanged += OnCollectionChanged;
// todo this is hack
if (typeof(T) == typeof(Point))
{
xyMapping = t => (Point)(object)t;
}
}
public ObservableDataSource(IEnumerable<T> data)
: this()
{
if (data == null)
throw new ArgumentNullException("data");
foreach (T item in data)
{
collection.Add(item);
}
}
public void SuspendUpdate()
{
updatesEnabled = false;
}
public void ResumeUpdate()
{
updatesEnabled = true;
if (collectionChanged)
{
collectionChanged = false;
RaiseDataChanged();
}
}
private void OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (updatesEnabled)
{
RaiseDataChanged();
}
else
{
collectionChanged = true;
}
}
private readonly ObservableCollection<T> collection = new ObservableCollection<T>();
public ObservableCollection<T> Collection
{
get { return collection; }
}
public void AppendMany(IEnumerable<T> data)
{
if (data == null)
throw new ArgumentNullException("data");
updatesEnabled = false;
foreach (var p in data)
{
collection.Add(p);
}
updatesEnabled = true;
RaiseDataChanged();
}
public void AppendAsync(Dispatcher dispatcher, T item)
{
dispatcher.Invoke(DispatcherPriority.Normal,
new Action(() =>
{
collection.Add(item);
RaiseDataChanged();
}));
}
private readonly List<Mapping<T>> mappings = new List<Mapping<T>>();
private Func<T, double> xMapping;
private Func<T, double> yMapping;
private Func<T, Point> xyMapping;
public void SetXMapping(Func<T, double> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.xMapping = mapping;
}
public void SetYMapping(Func<T, double> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.yMapping = mapping;
}
public void SetXYMapping(Func<T, Point> mapping)
{
if (mapping == null)
throw new ArgumentNullException("mapping");
this.xyMapping = mapping;
}
#region IChartDataSource Members
private class ObservableIterator : IPointEnumerator
{
private readonly ObservableDataSource<T> dataSource;
private readonly IEnumerator<T> enumerator;
public ObservableIterator(ObservableDataSource<T> dataSource)
{
this.dataSource = dataSource;
enumerator = dataSource.collection.GetEnumerator();
}
#region IChartPointEnumerator Members
public bool MoveNext()
{
return enumerator.MoveNext();
}
public void GetCurrent(ref Point p)
{
dataSource.FillPoint(enumerator.Current, ref p);
}
public void ApplyMappings(DependencyObject target)
{
dataSource.ApplyMappings(target, enumerator.Current);
}
public void Dispose()
{
enumerator.Dispose();
GC.SuppressFinalize(this);
}
#endregion
}
private void FillPoint(T elem, ref Point point)
{
if (xyMapping != null)
{
point = xyMapping(elem);
}
else
{
if (xMapping != null)
{
point.X = xMapping(elem);
}
if (yMapping != null)
{
point.Y = yMapping(elem);
}
}
}
private void ApplyMappings(DependencyObject target, T elem)
{
if (target != null)
{
foreach (var mapping in mappings)
{
target.SetValue(mapping.Property, mapping.F(elem));
}
}
}
public IPointEnumerator GetEnumerator(DependencyObject context)
{
return new ObservableIterator(this);
}
public event EventHandler DataChanged;
private void RaiseDataChanged()
{
if (DataChanged != null)
{
DataChanged(this, EventArgs.Empty);
}
}
#endregion
}
}

View File

@@ -0,0 +1,14 @@
using System.Collections.Generic;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
public sealed class RawDataSource : EnumerableDataSourceBase<Point> {
public RawDataSource(params Point[] data) : base(data) { }
public RawDataSource(IEnumerable<Point> data) : base(data) { }
public override IPointEnumerator GetEnumerator(DependencyObject context) {
return new RawPointEnumerator(this);
}
}
}

View File

@@ -0,0 +1,29 @@
using System.Collections;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
public sealed class RawPointEnumerator : IPointEnumerator {
private readonly IEnumerator enumerator;
public RawPointEnumerator(RawDataSource dataSource) {
this.enumerator = dataSource.Data.GetEnumerator();
}
public bool MoveNext() {
return enumerator.MoveNext();
}
public void GetCurrent(ref Point p) {
p = (Point)enumerator.Current;
}
public void ApplyMappings(DependencyObject target) {
// do nothing here - no mapping supported
}
public void Dispose() {
// do nothing here
}
}
}

View File

@@ -0,0 +1,32 @@
using System.Data;
using System.Linq;
using System.Windows;
using System.Collections.Generic;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>Data source that extracts sequence of points and their attributes from DataTable</summary>
public class TableDataSource : EnumerableDataSource<DataRow>
{
public TableDataSource(DataTable table)
: base(table.Rows)
{
// Subscribe to DataTable events
table.TableNewRow += NewRowInsertedHandler;
table.RowChanged += RowChangedHandler;
table.RowDeleted += RowChangedHandler;
}
private void RowChangedHandler(object sender, DataRowChangeEventArgs e)
{
RaiseDataChanged();
}
private void NewRowInsertedHandler(object sender, DataTableNewRowEventArgs e)
{
// Raise DataChanged event. ChartPlotter should redraw graph.
// This will be done automatically when rows are added to table.
RaiseDataChanged();
}
}
}