下面是我自己使用业余时间实现的silverlight chart area , 并组合两个chart area实现了google fiancial chart . 下面是截图和代码。仅供参考和学习。
Helpers:
public class AxisHelper
{
public static void DrawAxis(ChartArea area, bool isXAxis)
{
GradeSetting gs = isXAxis ? area.XGradeSetting : area.YGradeSetting;
var gls = area.Space.GetGradedLabels(gs, isXAxis);
if (gls == null || gls.Count() == 0)
return;
PathFigure pf = isXAxis ? area.xpf : area.ypf;
pf.StartPoint = new Point(area.Space.StartPoint.X, area.Space.StartPoint.Y);
pf.Segments.Clear();
//start
LineSegment sls = new LineSegment();
sls.Point = new Point(area.Space.StartPoint.X, area.Space.StartPoint.Y);
pf.Segments.Add(sls);
//End point
var els = new LineSegment();
SPoint sp = isXAxis ? area.Space.XEndPoint : area.Space.YEndPoint;
els.Point = new Point(sp.X, sp.Y);
pf.Segments.Add(els);
foreach (var gl in gls)
{
Grid g = new Grid();
if (isXAxis)
{
g.RowDefinitions.Add(new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) });
g.RowDefinitions.Add(new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) });
g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0, GridUnitType.Auto) });
}
else
{
g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0, GridUnitType.Auto) });
g.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(0, GridUnitType.Auto) });
g.RowDefinitions.Add(new RowDefinition { Height = new GridLength(0, GridUnitType.Auto) });
}
var cag = new ChartAreaGrid { Area = area, Margin = gl.Grade };
g.Tag = cag;
//grade
Rectangle r = new Rectangle
{
Width = gs.GradeWidth,
Height = gs.GradeHeigh,
Fill = new SolidColorBrush(Colors.Black),
HorizontalAlignment = HorizontalAlignment.Center
};
r.SetValue(isXAxis ? Grid.RowProperty : Grid.ColumnProperty, isXAxis ? 0 : 1);
g.Children.Add(r);
g.SizeChanged += new SizeChangedEventHandler(gy_SizeChanged);
//label
TextBlock txt = new TextBlock { Text = gl.Label, HorizontalAlignment = HorizontalAlignment.Center };
txt.SetValue(isXAxis ? Grid.RowProperty : Grid.ColumnProperty, isXAxis ? 1 : 0);
g.Children.Add(txt);
area.canvas.Children.Add(g);
}
}
static void gy_SizeChanged(object sender, SizeChangedEventArgs e)
{
Grid g = sender as Grid;
ChartAreaGrid cag = g.Tag as ChartAreaGrid;
if (g.ColumnDefinitions.Count == 2)
{
g.SetValue(Canvas.LeftProperty, cag.Area.Space.StartPoint.X - e.NewSize.Width + cag.Area.YGradeSetting.GradeWidth / 2);
g.SetValue(Canvas.TopProperty, cag.Margin - e.NewSize.Height / 2);
}
else
{
g.SetValue(Canvas.LeftProperty, cag.Margin - cag.Area.XGradeSetting.GradeWidth / 2 - e.NewSize.Width / 2);
g.SetValue(Canvas.TopProperty, cag.Area.Space.StartPoint.Y - cag.Area.YGradeSetting.GradeHeigh / 2);
}
}
class ChartAreaGrid
{
public ChartArea Area { get; set; }
public double Margin { get; set; }
}
public static void DrawTopLeftAxis(ChartArea area)
{
PathFigure pf = area.trpf;
pf.StartPoint = new Point(area.Space.YEndPoint.X , area.Space.YEndPoint .Y );
pf.Segments.Clear();
//start
LineSegment sls = new LineSegment();
sls.Point = new Point(area.Space.XEndPoint.X , area.Space.YEndPoint.Y );
pf.Segments.Add(sls);
//End point
var els = new LineSegment();
els.Point = new Point(area.Space.XEndPoint.X ,area .Space .XEndPoint .Y );
pf.Segments.Add(els);
}
}
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using SLPocs.Helpers;
using System.Linq;
using System.Collections.Generic;
using SLPocs.Entities;
namespace SLPocs.Controls.Charts
{
public class SeriesHelper
{
public static void DrawLinealSries(ChartArea area)
{
foreach (var pth in area.Space.Pathes)
{
DrawLinealSeries(area, pth);
}
}
static void DrawLinealSeries(ChartArea area, SPath pth)
{
Path p = new Path();
area.canvas.Children.Add(p);
p.Stroke = new SolidColorBrush(pth.Color);
p.StrokeThickness = 2;
PathGeometry pg = new PathGeometry();
p.Data = pg;
PathFigure fig = new PathFigure();
pg.Figures.Add(fig);
fig.StartPoint = new Point(pth[0].X, pth[0].Y);
foreach (var pnt in pth)
{
var ls = new LineSegment();
ls.Point = new Point(pnt.X, pnt.Y);
fig.Segments.Add(ls);
}
}
}
}
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.Generic;
using System.Linq;
namespace SLPocs.Controls.Charts
{
public class UerActionHelper
{
public static void AddResponseElement(ChartArea area, TraceType traceType)
{
switch (traceType)
{
case TraceType.CrossLine :
ShowCross(area);
break;
case TraceType.EllipseTrace :
ShowEllipses(area);
break;
case TraceType.SelectRange :
ShowSelector(area);
break;
}
}
public static void ShowCross(ChartArea area)
{
Line xline = new Line();
xline.Tag = "xline";
xline.X1 = area.Space.YEndPoint.X;
xline.Y1 = area.Space.YEndPoint.Y;
xline.X2 = area.Space.StartPoint.X;
xline.Y2 = area.Space.StartPoint.Y;
xline.Stroke = new SolidColorBrush(Colors.Green);
xline.StrokeThickness = 2;
area.canvas.Children.Add(xline);
Line yline = new Line();
yline.Tag = "yline";
yline.X1 = area.Space.StartPoint.X;
yline.Y1 = area.Space.StartPoint.Y;
yline.X2 = area.Space.XEndPoint.X;
yline.Y2 = area.Space.XEndPoint.Y; ;
yline.Stroke = new SolidColorBrush(Colors.Green);
yline.StrokeThickness = 2;
area.canvas.Children.Add(yline);
}
private static void ShowEllipses(ChartArea area)
{
foreach (var sp in area.Space.Pathes)
{
Ellipse eps = new Ellipse();
eps.Tag = sp.Key;
eps.Height = 6;
eps.Width = 6;
eps.Fill = new SolidColorBrush(sp.Color );
area.canvas.Children.Add(eps);
eps.SetValue(Canvas.LeftProperty, 0.0);
eps.SetValue(Canvas.TopProperty, 0.0);
eps.Visibility = Visibility.Collapsed;
}
}
private static void ShowSelector(ChartArea area)
{
throw new NotImplementedException();
}
public static void MoveResponseElements(ChartArea area, MouseEventArgs e)
{
switch (area.TraceType)
{
case TraceType.CrossLine :
MoveCrossLine(area, e);
break;
case TraceType.EllipseTrace :
MoveEllipses(area, e);
break;
}
}
static void MoveEllipses(ChartArea area, MouseEventArgs e)
{
double x = e.GetPosition(area.canvas).X;
var ys = area.Space.GetYPiexes(x);
var ells = area.canvas.Children.Where(a => a is Ellipse).Select(a=>a as Ellipse ).ToList();
foreach (var pth in area.Space.Pathes)
{
double? y = ys[pth.Key];
var ell = ells.First(a => a.Tag == pth.Key);
if (x < area.Space.StartPoint.X || x > area.Space.XEndPoint.X || !y.HasValue )
ell.Visibility = Visibility.Collapsed;
else
{
ell.Visibility = Visibility.Visible;
ell.SetValue(Canvas.TopProperty, y.Value-ell.Height/2);
ell.SetValue(Canvas.LeftProperty, x-ell.Width/2);
}
}
}
static void MoveCrossLine(ChartArea area, MouseEventArgs e)
{
var lines = area .canvas.Children.Where(x => x is Line);
foreach (var line in lines)
{
var l = line as Line;
if (l.Tag == "xline")
{
double x = e.GetPosition(area. canvas).X;
if (x > area.Space.XEndPoint.X)
x = area.Space.XEndPoint.X;
else if (x < area.Space.StartPoint.X)
x = area.Space.StartPoint.X;
l.X1 = x;
l.X2 = x;
}
else
{
double y = e.GetPosition(area.canvas).Y;
if (y > area.Space.StartPoint.Y)
y = area.Space.StartPoint.Y;
else if (y < area.Space.YEndPoint.Y)
y = area.Space.YEndPoint.Y;
l.Y1 = y;
l.Y2 = y;
}
}
}
}
}
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Data;
namespace SLPocs.Controls
{
public class BindingHelper
{
public static void SetBindindFromSource(DependencyObject control, DependencyProperty property, object source, string path, BindingMode mode = BindingMode.OneWay, IValueConverter converter = null, UpdateSourceTrigger updateTrigger = UpdateSourceTrigger.Default)
{
Binding binding = new Binding();
binding.Path = new PropertyPath(path);
binding.Mode = mode;
binding.Source = source;
binding.Converter = converter;
BindingOperations.SetBinding(control , property, binding);
}
}
}
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using System.Collections.Generic;
namespace SLPocs.Helpers
{
public class DynamicHelper
{
public static Func<object, object> GetSelector(Type T, string property)
{
var o = System.Linq.Expressions.Expression.Variable(typeof(object));
var block = System.Linq.Expressions.Expression.Block(
System.Linq.Expressions.Expression.Convert(
System.Linq.Expressions.Expression.Property(System.Linq.Expressions.Expression.Convert(o, T), property), typeof(object))
);
return System.Linq.Expressions.Expression.Lambda<Func<object, object>>(block, o).Compile();
}
public static object First(IEnumerable collection)
{
if (collection != null)
{
foreach (var o in collection)
return o;
}
return null;
}
public static IEnumerable<T> Select<T>(IEnumerable collection, Func<object, object> selector)
{
foreach (var o in collection)
yield return (T)selector(o);
}
}
}
using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLPocs.Entities;
namespace SLPocs.Helpers
{
public class MathHelper
{
public static double GetLineValue(double x, double x0, double y0, double x1, double y1)
{
return y0 + (y1 - y0) * (x - x0) / (x1 - x0);
}
public static double ConvertDatetimeToDouble(DateTime dt, DateTime from, TimeUnit tu)
{
if (tu == TimeUnit.Year)
return dt.Year - from.Year;
if (tu == TimeUnit.Month)
return 12 * (dt.Year - from.Year) + dt.Month - from.Month;
if (tu == TimeUnit.Day)
return (dt - from).TotalDays;
if (tu == TimeUnit.Hour)
return (dt - from).TotalHours;
if (tu == TimeUnit.Min)
return (dt - from).TotalMinutes;
if (tu == TimeUnit.Second)
return (dt - from).TotalSeconds;
if (tu == TimeUnit.MinSecond)
return (dt - from).TotalMilliseconds;
return 0;
}
public static DateTime AddTime(double add, DateTime from, TimeUnit tu)
{
if (tu == TimeUnit.Year)
return from.AddYears((int)add);
if (tu == TimeUnit.Month)
return from.AddMonths((int)add);
if (tu == TimeUnit.Day)
return from.AddDays((int)add);
if (tu == TimeUnit.Hour)
return from.AddHours(add);
if (tu == TimeUnit.Min)
return from.AddMinutes(add);
if (tu == TimeUnit.Second)
return from.AddSeconds(add);
if (tu == TimeUnit.MinSecond)
return from.AddMilliseconds(add);
return from;
}
public static void Shrink(FrameworkElement element, double xrate, double yrate)
{
element.Width = element.Width * xrate;
element.Height = element.Height * yrate;
double value = (double)element.GetValue(Canvas.LeftProperty);
element.SetValue(Canvas.LeftProperty, value * xrate);
value = (double)element.GetValue(Canvas.TopProperty);
element.SetValue(Canvas.TopProperty, value * yrate);
}
}
}
XAML
<UserControl xmlns:my="clr-namespace:SLPocs.Controls.Charts" x:Class="SLPocs.Controls.Charts.ChartArea"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<UserControl.Resources >
<Grid x:Key="rangeSelector">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="Auto"></ColumnDefinition>
</Grid.ColumnDefinitions>
<sdk:GridSplitter x:Name="leftSplitter"
Grid.Column="1"
VerticalAlignment="Stretch"
Width="2"
HorizontalAlignment="Left"
Background="Gray"></sdk:GridSplitter>
<sdk:GridSplitter x:Name="rightSplitter"
Grid.Column="1"
VerticalAlignment="Stretch"
Width="2"
HorizontalAlignment="Right"
Background="Gray"></sdk:GridSplitter>
<Border x:Name="selector_Bdr"
Grid.Column="1"
BorderThickness="0,2,0,2"
BorderBrush="Gray"
Background="Gray"
Opacity="0.1"
Margin="2" AllowDrop="True" ></Border>
</Grid>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" MouseMove="LayoutRoot_MouseMove" Background="White" ShowGridLines="True">
<Canvas x:Name="canvas" Background="Transparent">
</Canvas>
<my:RangeSelector x:Name="rangeSelector" />
<Path x:Name="XAxis"
Stroke="Black"
StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="xpf">
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path x:Name="YAxis"
Stroke="Black"
StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="ypf">
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path x:Name="TopRightAxis"
Stroke="Black"
StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure x:Name="trpf">
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</UserControl>
<UserControl x:Class="SLPocs.Controls.Charts.RangeSelector"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"
mc:Ignorable="d"
Background="Transparent"
HorizontalAlignment="Stretch" VerticalAlignment="Stretch"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="Transparent" >
<Canvas x:Name="selectorCanvas" Background="Transparent" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Border x:Name="leftSelectorGrid"
BorderThickness="0"
Width="5"
Background="Gray"
MouseLeftButtonDown="leftSelectorGrid_MouseLeftButtonDown"
MouseLeftButtonUp="leftSelectorGrid_MouseLeftButtonUp"
MouseMove="leftSelectorGrid_MouseMove"></Border>
<Border x:Name="selector"
BorderThickness="0,2,0,2"
Background="Gray"
Opacity="0.2"
MouseLeftButtonDown="selector_MouseLeftButtonDown"
MouseLeftButtonUp="selector_MouseLeftButtonUp"
MouseMove="selector_MouseMove"></Border>
<Border x:Name="rightSelectorGrid"
BorderThickness="0"
Width="5"
Background="Gray"
MouseLeftButtonDown="rightSelectorGrid_MouseLeftButtonDown"
MouseLeftButtonUp="rightSelectorGrid_MouseLeftButtonUp"
MouseMove="rightSelectorGrid_MouseMove"></Border>
</Canvas>
</Grid>
</UserControl>
Behind code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections;
using SLPocs.Entities;
using System.Windows.Data;
namespace SLPocs.Controls.Charts
{
public partial class ChartArea : UserControl
{
public ChartArea()
{
InitializeComponent();
this.SizeChanged += new SizeChangedEventHandler(ChartArea_SizeChanged);
Space = new LinealSpace();
Space.SetStartPoint(MarginX, MarginY+100);
Space.SetLength(100, 100);
rangeSelector.StartPercValue = 0.7;
rangeSelector.EndPercValue = 0.9;
rangeSelector.UpdateRangeAction = this.HandelSelectedItemsChanged;
}
public Size Size;
protected override Size ArrangeOverride(Size finalSize)
{
Size = base.ArrangeOverride(finalSize);
return Size;
}
bool initialized = false;
void ChartArea_SizeChanged(object sender, SizeChangedEventArgs e)
{
UpdateUI();
initialized = true;
}
public void UpdateUI()
{
Space.SetLength(this.Size.Width - 2 * MarginX, this.Size.Height - 2 * MarginY);
Space.SetStartPoint(MarginX, this.Size.Height - MarginY);
canvas.Children.Clear();
SeriesHelper.DrawLinealSries(this);
AxisHelper.DrawAxis(this, false);
AxisHelper.DrawAxis(this, true);
if (isRangeSelector)
{
InitializeRangeSelectorSpace();
AxisHelper.DrawTopLeftAxis(this);
}
else
rangeSelector.Visibility = System.Windows.Visibility.Collapsed;
if(isTrace )
UerActionHelper.AddResponseElement(this, this.TraceType); ;
}
public LinealSpace Space = null;
IEnumerable dataSource;
public IEnumerable DataSource
{
get { return dataSource ; }
set
{
dataSource = value;
Space.FillData(dataSource, XPath, XGradeSetting .TimeUnit,IsRangeSeletor , YPaths);
if (initialized)
UpdateUI();
}
}
public IEnumerable selectedItems;
public IEnumerable SelectedItems { get { return selectedItems; } }
public Action<IEnumerable> UpdateSelectedItems { get; set; }
public void HandelSelectedItemsChanged(double start, double end)
{
if (isRangeSelector)
{
double xlen= Space.XEndPoint .X -Space.StartPoint .X ;
double _start = xlen * start + Space.StartPoint.X, _end = xlen * end + Space.StartPoint.X;
selectedItems = Space.Pathes[0].Where(x => x.X >= _start && x.X < _end).Select(x => x.Item);
if (UpdateSelectedItems != null)
UpdateSelectedItems(selectedItems);
}
}
public TraceType TraceType = TraceType.CrossLine;
public string Caption { get; set; }
#region XAxis Settings
public double MarginX = 100;
public string XPath = "X";
public GradeSetting XGradeSetting = new GradeSetting {
FixedPoints = 10,
Format = "yyyy/MM/dd",
GradeHeigh = 4,
GradeWidth = 2,
Internl = 100,
GradeType = GradeType.FixedInternal,
TimeUnit = TimeUnit.Day
};
#endregion
#region YAxis Settings
public string[] YPaths = new string[]{"Y1","Y2","Y3"};
public double MarginY = 100;
public GradeSetting YGradeSetting = new GradeSetting
{
FixedPoints = 10,
Format = "0.00",
GradeHeigh = 2,
GradeWidth = 4,
Internl = 10,
GradeType = GradeType.FixedInternal,
TimeUnit = TimeUnit.Day
};
#endregion
#region Selector
bool isRangeSelector = true;
public bool IsRangeSeletor { get { return isRangeSelector; } set { isRangeSelector = value; } }
void InitializeRangeSelectorSpace()
{
rangeSelector.Width = Space.XEndPoint.X - Space.StartPoint.X;
rangeSelector.Height = Space.StartPoint.Y - Space.YEndPoint.Y;
rangeSelector.Margin = new Thickness { Bottom = MarginX, Top = MarginX, Left = MarginY, Right = MarginY };
}
#endregion
#region User Response
bool isTrace = true;
public bool IsTrace { get { return isTrace; } set { isTrace = value; } }
private void LayoutRoot_MouseMove(object sender, MouseEventArgs e)
{
if (isTrace)
UerActionHelper.MoveResponseElements(this, e);
}
#endregion
}
public enum TraceType
{
CrossLine,
EllipseTrace,
SelectRange,
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLPocs.Helpers;
namespace SLPocs.Controls.Charts
{
public partial class RangeSelector : UserControl
{
public RangeSelector()
{
InitializeComponent();
this.SizeChanged += new SizeChangedEventHandler(RangeSelector_SizeChanged);
leftSelectorGrid.Cursor = Cursors.SizeWE;
selector.Cursor = Cursors.Hand;
rightSelectorGrid.Cursor = Cursors.SizeWE;
}
public Action<double, double> UpdateRangeAction { get; set; }
public double StartPercValue { get; set; }
public double EndPercValue { get; set; }
Size size;
void RangeSelector_SizeChanged(object sender, SizeChangedEventArgs e)
{
size = e.NewSize;
UpdateUI();
}
private void UpdateUI()
{
leftSelectorGrid.Height = size.Height;
leftSelectorGrid.SetValue(Canvas.LeftProperty, size.Width * StartPercValue-leftSelectorGrid.Width);
selector.Height = size.Height;
selector.Width = size.Width * (EndPercValue - StartPercValue);
selector.SetValue(Canvas.LeftProperty, size.Width * StartPercValue);
rightSelectorGrid.Height = size.Height;
rightSelectorGrid.SetValue(Canvas.LeftProperty, size.Width * StartPercValue + selector.Width);
}
double preLX;
bool isLMouseCaptured;
private void leftSelectorGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
SetPreX(sender, e, ref preLX,ref isLMouseCaptured);
}
private void leftSelectorGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
HandleRelease(sender, e, ref preLX, ref isLMouseCaptured);
}
private void leftSelectorGrid_MouseMove(object sender, MouseEventArgs e)
{
HandleMove(sender, e, ref preLX, isLMouseCaptured,true );
}
double preSX;
bool isSMouseCaptured;
private void selector_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
SetPreX(sender ,e ,ref preSX ,ref isSMouseCaptured );
}
private void selector_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
HandleRelease(sender, e, ref preSX, ref isSMouseCaptured);
}
private void selector_MouseMove(object sender, MouseEventArgs e)
{
HandleMove(sender, e, ref preSX, isSMouseCaptured,null );
}
double preRX;
bool isRMouseCaptured;
private void rightSelectorGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
SetPreX(sender, e, ref preRX, ref isRMouseCaptured);
}
private void rightSelectorGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
HandleRelease(sender, e, ref preRX, ref isRMouseCaptured);
}
private void rightSelectorGrid_MouseMove(object sender, MouseEventArgs e)
{
HandleMove(sender, e, ref preRX, isRMouseCaptured,false);
}
void SetPreX(object sender, MouseEventArgs e, ref double px,ref bool isCaptured)
{
Border item = sender as Border;
px = e.GetPosition(selectorCanvas).X;
if (px < 0)
px = 0;
else if (px > size.Width)
px = size.Width;
item.CaptureMouse();
isCaptured = true;
}
void HandleMove(object sender, MouseEventArgs e, ref double px, bool isCaptured,bool? isLeft)
{
Border item = sender as Border;
if (isCaptured)
{
double itemX = (double)item.GetValue(Canvas.LeftProperty);
double ex = e.GetPosition(selectorCanvas).X;
if (ex < 0)
ex = 0;
else if (ex > size.Width)
ex = size.Width;
double deltaX =ex- px;
if (deltaX < 0 && deltaX + itemX < 0)
StartPercValue = 0;
else if (deltaX > 0 && itemX + item.Width + deltaX > size.Width)
EndPercValue = 1;
else if (isLeft.HasValue && isLeft.Value)
StartPercValue += deltaX / size.Width;
else if (isLeft.HasValue && !isLeft.Value)
EndPercValue += deltaX / size.Width;
else
{
StartPercValue += deltaX / size.Width;
EndPercValue += deltaX / size.Width;
}
UpdateUI();
// Update position global variables.
px = ex;
}
}
void HandleRelease(object sender, MouseEventArgs e, ref double px, ref bool isCaptured)
{
Border item = sender as Border;
isCaptured = false;
item.ReleaseMouseCapture();
if (UpdateRangeAction != null)
UpdateRangeAction(StartPercValue, EndPercValue);
}
}
public struct RectangleArea
{
public double X1 { get; set; }
public double Y1 { get; set; }
public double X2 { get; set; }
public double Y2 { get; set; }
public bool IsRelative { get; set; }
public void Shrink(double xrate, double yrate)
{
X1 *= xrate;
X2 *= xrate;
Y1 *= yrate;
Y2 *= yrate;
}
}
}
How to use it
<UserControl xmlns:my1="clr-namespace:SLPocs.Controls.Charts" xmlns:syncfusion="clr-namespace:Syncfusion.Windows.Chart;assembly=Syncfusion.Chart.Silverlight" xmlns:my="clr-namespace:SLPocs.Controls.Grids" x:Class="SLPocs.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions >
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="400"></RowDefinition>
</Grid.RowDefinitions>
<my1:ChartArea x:Name="detail"/>
<my1:ChartArea x:Name="summary" Grid.Row="1" />
</Grid>
</UserControl>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using SLPocs.Controls.Texts;
using SLPocs.Controls.Arrows;
using SLPocs.Controls.Charts;
using SLPocs.Controls;
using System.Collections.ObjectModel;
using SLPocs.Entities;
using System.Windows.Markup;
using System.Collections;
namespace SLPocs
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
summary.DataSource = TestChartData.GetTestData();
summary.IsTrace = false;
summary.TraceType = TraceType.EllipseTrace;
summary.XGradeSetting.GradeType = GradeType.FixedInternal;
summary.UpdateSelectedItems = this.UpdateSelectedItems;
detail.IsTrace = true;
detail.IsRangeSeletor = false;
detail.TraceType = TraceType.EllipseTrace;
detail.XGradeSetting.GradeType = GradeType.FixedPoints ;
}
void UpdateSelectedItems(IEnumerable data)
{
detail.DataSource = data;
}
}
public class TestChartData
{
public double Y1 { get; set; }
public double Y2 { get; set; }
public double Y3 { get; set; }
public DateTime X { get; set; }
public static IEnumerable<TestChartData> GetTestData()
{
for (int i = 0; i < 2000; i++)
yield return new TestChartData
{
Y1 =100+ 50*Math.Sin(Math.PI *i/60),
Y2 = 100 + 50 * Math.Sin(Math.PI * i / 60+Math.PI /4),
Y3 = 100 + 50 * Math.Sin(Math.PI * i / 60+Math.PI/2),
X = DateTime.Now .AddDays (i ),
};
}
}
}