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,51 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources.MultiDimensional
{
public static class DataSource2DHelper
{
public static Point[,] CreateUniformGrid(int width, int height, double gridWidth, double gridHeight)
{
return CreateUniformGrid(width, height, 0, 0, gridWidth / width, gridHeight / height);
}
public static Point[,] CreateUniformGrid(int width, int height, double xStart, double yStart, double xStep, double yStep)
{
Point[,] result = new Point[width, height];
double x = xStart;
for (int ix = 0; ix < width; ix++)
{
double y = yStart;
for (int iy = 0; iy < height; iy++)
{
result[ix, iy] = new Point(x, y);
y += yStep;
}
x += xStep;
}
return result;
}
public static Vector[,] CreateVectorData(int width, int height, Func<int, int, Vector> generator)
{
Vector[,] result = new Vector[width, height];
for (int ix = 0; ix < width; ix++)
{
for (int iy = 0; iy < height; iy++)
{
result[ix, iy] = generator(ix, iy);
}
}
return result;
}
}
}

View File

@@ -0,0 +1,75 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources.MultiDimensional
{
/// <summary>
/// Defines empty two-dimensional data source.
/// </summary>
/// <typeparam name="T"></typeparam>
public sealed class EmptyDataSource2D<T> : IDataSource2D<T> where T : struct
{
#region IDataSource2D<T> Members
private T[,] data = new T[0, 0];
public T[,] Data
{
get { return data; }
}
private Point[,] grid = new Point[0, 0];
public Point[,] Grid
{
get { return grid; }
}
public int Width
{
get { return 0; }
}
public int Height
{
get { return 0; }
}
private void RaiseChanged()
{
if (Changed != null)
{
Changed(this, EventArgs.Empty);
}
}
public event EventHandler Changed;
#endregion
#region IDataSource2D<T> Members
public Microsoft.Research.DynamicDataDisplay.Charts.Range<T>? Range
{
get { throw new NotImplementedException(); }
}
public T? MissingValue
{
get { throw new NotImplementedException(); }
}
#endregion
#region IDataSource2D<T> Members
public IDataSource2D<T> GetSubset(int x0, int y0, int countX, int countY, int stepX, int stepY)
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.Charts;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
/// <summary>
/// General interface for two-dimensional data source. Contains two-dimensional array of data items.
/// </summary>
/// <typeparam name="T">Data type - type of each data piece.</typeparam>
public interface IDataSource2D<T> : IGridSource2D where T : struct
{
/// <summary>
/// Gets two-dimensional data array.
/// </summary>
/// <value>The data.</value>
T[,] Data { get; }
IDataSource2D<T> GetSubset(int x0, int y0, int countX, int countY, int stepX, int stepY);
Range<T>? Range { get; }
T? MissingValue { get; }
}
/// <summary>
/// General interface for two-dimensional data grids. Contains two-dimensional array of data points.
/// </summary>
public interface IGridSource2D
{
/// <summary>
/// Gets the grid of data source.
/// </summary>
/// <value>The grid.</value>
Point[,] Grid { get; }
/// <summary>
/// Gets data grid width.
/// </summary>
/// <value>The width.</value>
int Width { get; }
/// <summary>
/// Gets data grid height.
/// </summary>
/// <value>The height.</value>
int Height { get; }
/// <summary>
/// Occurs when data source changes.
/// </summary>
event EventHandler Changed;
}
}

View File

@@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Microsoft.Research.DynamicDataDisplay.DataSources
{
public interface INonUniformDataSource2D<T> : IDataSource2D<T> where T : struct
{
double[] XCoordinates { get; }
double[] YCoordinates { get; }
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
namespace Microsoft.Research.DynamicDataDisplay.DataSources.MultiDimensional
{
public class NonUniformDataSource2D<T> : INonUniformDataSource2D<T> where T : struct
{
public NonUniformDataSource2D(double[] xcoordinates, double[] ycoordinates, T[,] data)
{
if (xcoordinates == null)
throw new ArgumentNullException("xcoordinates");
if (ycoordinates == null)
throw new ArgumentNullException("ycoordinates");
if (data == null)
throw new ArgumentNullException("data");
this.xCoordinates = xcoordinates;
this.yCoordinates = ycoordinates;
BuildGrid();
this.data = data;
}
private void BuildGrid()
{
grid = new Point[Width, Height];
for (int iy = 0; iy < Height; iy++)
{
for (int ix = 0; ix < Width; ix++)
{
grid[ix, iy] = new Point(xCoordinates[ix], yCoordinates[iy]);
}
}
}
#region INonUniformDataSource2D<T> Members
private double[] xCoordinates;
public double[] XCoordinates
{
get { return xCoordinates; }
}
private double[] yCoordinates;
public double[] YCoordinates
{
get { return yCoordinates; }
}
#endregion
#region IDataSource2D<T> Members
private T[,] data;
public T[,] Data
{
get { return data; }
}
public IDataSource2D<T> GetSubset(int x0, int y0, int countX, int countY, int stepX, int stepY)
{
throw new NotImplementedException();
}
public void ApplyMappings(DependencyObject marker, int x, int y)
{
throw new NotImplementedException();
}
#endregion
#region IGridSource2D Members
private Point[,] grid;
public Point[,] Grid
{
get { return grid; }
}
public int Width
{
get { return xCoordinates.Length; }
}
public int Height
{
get { return yCoordinates.Length; }
}
public event EventHandler Changed;
#endregion
#region IDataSource2D<T> Members
public Microsoft.Research.DynamicDataDisplay.Charts.Range<T>? Range
{
get { throw new NotImplementedException(); }
}
public T? MissingValue
{
get { throw new NotImplementedException(); }
}
#endregion
}
}

View File

@@ -0,0 +1,113 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using Microsoft.Research.DynamicDataDisplay.Common.Auxiliary;
namespace Microsoft.Research.DynamicDataDisplay.DataSources.MultiDimensional
{
/// <summary>
/// Defines warped two-dimensional data source.
/// </summary>
/// <typeparam name="T">Data piece type</typeparam>
public sealed class WarpedDataSource2D<T> : IDataSource2D<T> where T : struct
{
/// <summary>
/// Initializes a new instance of the <see cref="WarpedDataSource2D&lt;T&gt;"/> class.
/// </summary>
/// <param name="data">Data.</param>
/// <param name="grid">Grid.</param>
public WarpedDataSource2D(T[,] data, Point[,] grid)
{
if (data == null)
throw new ArgumentNullException("data");
if (grid == null)
throw new ArgumentNullException("grid");
Verify.IsTrue(data.GetLength(0) == grid.GetLength(0));
Verify.IsTrue(data.GetLength(1) == grid.GetLength(1));
this.data = data;
this.grid = grid;
width = data.GetLength(0);
height = data.GetLength(1);
}
#region DataSource<T> Members
private readonly T[,] data;
/// <summary>
/// Gets two-dimensional data array.
/// </summary>
/// <value>The data.</value>
public T[,] Data
{
get { return data; }
}
private readonly Point[,] grid;
/// <summary>
/// Gets the grid of data source.
/// </summary>
/// <value>The grid.</value>
public Point[,] Grid
{
get { return grid; }
}
private readonly int width;
/// <summary>
/// Gets data grid width.
/// </summary>
/// <value>The width.</value>
public int Width
{
get { return width; }
}
private readonly int height;
/// <summary>
/// Gets data grid height.
/// </summary>
/// <value>The height.</value>
public int Height
{
get { return height; }
}
public IDataSource2D<T> GetSubset(int x0, int y0, int countX, int countY, int stepX, int stepY)
{
throw new NotImplementedException();
}
private void RaiseChanged()
{
if (Changed != null)
{
Changed(this, EventArgs.Empty);
}
}
/// <summary>
/// Occurs when data source changes.
/// </summary>
public event EventHandler Changed;
#endregion
#region IDataSource2D<T> Members
public Microsoft.Research.DynamicDataDisplay.Charts.Range<T>? Range
{
get { throw new NotImplementedException(); }
}
public T? MissingValue
{
get { throw new NotImplementedException(); }
}
#endregion
}
}

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();
}
}
}