using Microsoft.VisualBasic.CompilerServices;
using MuchInfo.Chart.Data.EnumTypes;
using MuchInfo.Chart.Data.Interfaces;
using MuchInfo.Chart.Data.Models;
using MuchInfo.Chart.FormulaEdit;
using MuchInfo.Chart.Infrastructure.Data;
using MuchInfo.Chart.Infrastructure.Helpers;
using MuchInfo.Chart.Infrastructure.Utilities;
using MuchInfo.Chart.WPF.Controls.Drawing;
using MuchInfo.Chart.WPF.Controls.QuickTimeSpan;
using MuchInfo.Chart.WPF.Controls.ValueScaling;
using MuchInfo.Chart.WPF.Helpers;
using MuchInfo.Chart.WPF.Primitives;
using MuchInfo.Chart.WPF.Primitives.Drawing;
using MuchInfo.Chart.WPF.Primitives.Interfaces;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Shapes;
using System.Windows.Threading;
using Xceed.Wpf.Toolkit;
namespace MuchInfo.Chart.WPF
{
#region Delegates
///
/// 通过CycleType加载历史周期数据
///
/// 交易所代码
/// 商品代码
/// 周期
/// 起始时间
/// 结束时间
/// 数据前N条
/// List{ILineDataPoint}.
public delegate List LoadHistoryCycleDataByCycleTypeEventHandler(int exchangeCode, string goodsCode, CycleType type, TimeSpan timeSpan, DateTime startTime, DateTime endTime, int topN);
#endregion Delegates
///
/// WPF图表控件
///
public class Chart : Control
{
#region 依赖属性
///
/// 左右键增减周期值
///
public static readonly DependencyProperty LeftRightKeyToAccelerationProperty =
DependencyProperty.Register("LeftRightKeyToAcceleration", typeof(int), typeof(Chart), new PropertyMetadata(10));
///
/// 鼠标滚轮加速缩放因数
///
public static readonly DependencyProperty AcceleratedWheelFactorProperty =
DependencyProperty.Register("AcceleratedWheelFactor", typeof(int), typeof(Chart), new PropertyMetadata(10));
///
/// 鼠标滚轮加速缩放键
///
public static readonly DependencyProperty AcceleratedWheelModifierKeysProperty =
DependencyProperty.Register("AcceleratedWheelModifierKeys", typeof(ModifierKeys), typeof(Chart),
new PropertyMetadata(ModifierKeys.Control));
///
/// 背景色
///
public static readonly DependencyProperty ChartBackgroundProperty =
DependencyProperty.Register("ChartBackground", typeof(SolidColorBrush), typeof(Chart),
new PropertyMetadata(new SolidColorBrush(Colors.Black),
new PropertyChangedCallback(Chart.ChartFontSizeProperty_Changed)));
///
/// 字体大小
///
public static readonly DependencyProperty ChartFontSizeProperty = DependencyProperty.Register("ChartFontSize",
typeof(double), typeof(Chart),
new PropertyMetadata(12d, new PropertyChangedCallback(Chart.ChartFontSizeProperty_Changed)));
///
/// 绘图类型
///
public static readonly DependencyProperty ChartLanguageProperty = DependencyProperty.Register("ChartLanguage",
typeof(ChartLanguageType), typeof(Chart),
new PropertyMetadata(ChartLanguageType.SimplifiedChinese,
new PropertyChangedCallback(Chart.ChartLanguageProperty_Changed)));
///
/// The chart time span property
///
public static readonly DependencyProperty ChartTimeSpanProperty = DependencyProperty.Register("ChartTimeSpan",
typeof(TimeSpan), typeof(Chart),
new PropertyMetadata(default(TimeSpan), Chart.ChartTimeSpanProperty_Changed));
///
/// The current goods property
///
public static readonly DependencyProperty CurrentGoodsProperty = DependencyProperty.Register("CurrentGoods",
typeof(GoodsInfo), typeof(Chart), new PropertyMetadata(null, Chart.CurrentGoodsProperty_Changed));
///
/// 商品周期
///
public static readonly DependencyProperty CycleTypeProperty = DependencyProperty.Register("CycleType",
typeof(CycleType), typeof(Chart),
new PropertyMetadata(CycleType.Minute, new PropertyChangedCallback(Chart.ChartCycleTypeProperty_Changed)));
///
/// 商品周期集合
///
public static readonly DependencyProperty CycleItemsProperty =
DependencyProperty.Register("CycleItems", typeof(List),
typeof(Chart), new PropertyMetadata(new List(), new PropertyChangedCallback(Chart.ChartCycleTypeItemsProperty_Changed)));
///
/// 当前Tik数据,只需更新Tik数据即可,控件自动累加
///
public BarDataPoint CurrentTik
{
get { return (BarDataPoint)GetValue(CurrentTikProperty); }
set { SetValue(CurrentTikProperty, value); }
}
public static readonly DependencyProperty CurrentTikProperty =
DependencyProperty.Register("CurrentTik", typeof(BarDataPoint), typeof(Chart),
new PropertyMetadata(null, new PropertyChangedCallback(Chart.ChartTikProperty_Changed)));
///
/// 画线工具位置
///
public static readonly DependencyProperty DrawingToolPositionProperty =
DependencyProperty.Register("DrawingToolPosition", typeof(DrawingToolPositionType), typeof(Chart),
new PropertyMetadata(DrawingToolPositionType.Left,
new PropertyChangedCallback(Chart.DrawingToolPositionProperty_Changed)));
///
/// 当前画线工具:可通过设置值来模拟画线工具单击事件
///
public static readonly DependencyProperty DrawingToolTypeProperty =
DependencyProperty.Register("DrawingToolType", typeof(DrawingToolType), typeof(Chart),
new PropertyMetadata(DrawingToolType.Cross, new PropertyChangedCallback(Chart.DrawingToolType_Changed)));
///
/// 蜡烛图叠加是否填充
///
public static readonly DependencyProperty FillComparisonCandleProperty =
DependencyProperty.Register("FillComparisonCandle", typeof(bool), typeof(Chart),
new PropertyMetadata(false, Chart.ChartProperty_Changed));
///
/// 网格透明度
///
public static readonly DependencyProperty GridOpacityProperty = DependencyProperty.Register("GridOpacity",
typeof(double), typeof(Chart),
new PropertyMetadata(0.15d, new PropertyChangedCallback(Chart.ChartProperty_Changed)));
///
/// 绘图类型
///
public static readonly DependencyProperty LinePlotTypeProperty = DependencyProperty.Register("LinePlotType",
typeof(LinePlotType), typeof(Chart),
new PropertyMetadata(LinePlotType.Candlestick,
new PropertyChangedCallback(Chart.ChartLineTypePlotProperty_Changed)));
///
/// 最大加载数据条数
///
public static readonly DependencyProperty MaxLoadRecordCountProperty =
DependencyProperty.Register("MaxLoadRecordCount", typeof(int), typeof(Chart), new PropertyMetadata(500));
///
/// 最大显示数据条数
///
public static readonly DependencyProperty MaxRecordCountProperty = DependencyProperty.Register(
"MaxRecordCount", typeof(int), typeof(Chart),
new PropertyMetadata(1000, new PropertyChangedCallback(Chart.ChartMinMaxRecordProperty_Changed)));
///
/// 最小显示数据条数
///
public static readonly DependencyProperty MinRecordCountProperty = DependencyProperty.Register(
"MinRecordCount", typeof(int), typeof(Chart),
new PropertyMetadata(50, new PropertyChangedCallback(Chart.ChartMinMaxRecordProperty_Changed)));
///
/// 显示数据条数
///
public static readonly DependencyProperty RecordCountProperty = DependencyProperty.Register("RecordCount",
typeof(int), typeof(Chart),
new PropertyMetadata(100, new PropertyChangedCallback(Chart.ChartRecordCountProperty_Changed)));
///
/// 是否显示画线工具
///
public static readonly DependencyProperty ShowDrawingToolProperty =
DependencyProperty.Register("ShowDrawingTool", typeof(Visibility), typeof(Chart),
new PropertyMetadata(Visibility.Visible,
new PropertyChangedCallback(ElementInvalidator.PropertyChanged_InvalidateMeasureArrange)));
///
/// 画图工具是否可用
///
public bool DrawingToolIsEnabled
{
get { return (bool)GetValue(DrawingToolIsEnabledProperty); }
set { SetValue(DrawingToolIsEnabledProperty, value); }
}
public static readonly DependencyProperty DrawingToolIsEnabledProperty =
DependencyProperty.Register("DrawingToolIsEnabled", typeof(bool), typeof(Chart), new PropertyMetadata(true));
///
/// 最多可显示多少个ChartPane
///
public int MaxChartPaneCount
{
get { return (int)GetValue(MaxChartPaneCountProperty); }
set { SetValue(MaxChartPaneCountProperty, value); }
}
public static readonly DependencyProperty MaxChartPaneCountProperty =
DependencyProperty.Register("MaxChartPaneCount", typeof(int), typeof(Chart), new PropertyMetadata(5));
///
/// 设置分时图网格与刻度的坐标
///
public Brush TimeSharingGridBrush
{
get { return (Brush)GetValue(TimeSharingGridBrushProperty); }
set { SetValue(TimeSharingGridBrushProperty, value); }
}
public static readonly DependencyProperty TimeSharingGridBrushProperty =
DependencyProperty.Register("TimeSharingGridBrush", typeof(Brush), typeof(Chart),
new PropertyMetadata(Brushes.Red));
///
/// 设置合适的边距缓冲区
///
public int RightBuffer
{
get { return (int)GetValue(RightBufferProperty); }
set { SetValue(RightBufferProperty, value); }
}
public static readonly DependencyProperty RightBufferProperty =
DependencyProperty.Register("RightBuffer", typeof(int), typeof(Chart), new PropertyMetadata(20));
public Visibility CycleBarVisibility
{
get { return (Visibility)GetValue(CycleBarVisibilityProperty); }
set { SetValue(CycleBarVisibilityProperty, value); }
}
// Using a DependencyProperty as the backing store for CycleBarVisibility. This enables animation, styling, binding, etc...
public static readonly DependencyProperty CycleBarVisibilityProperty =
DependencyProperty.Register("CycleBarVisibility", typeof(Visibility), typeof(Chart), new PropertyMetadata(Visibility.Visible, new PropertyChangedCallback(Chart.ChartCycleBarVisibity)));
///
/// 加载历史周期数据 By CycleType
///
public LoadHistoryCycleDataByCycleTypeEventHandler LoadHistoryCycleDataByCycleType;
///
/// drawLINE
///
private static IDrawingTool _oldDrawingTool;
//头容器
private StackPanel _chartHeaderStackPanel;
//chart pane容器
private Grid _chartPanesGrid;
private ChartToolbarExpander _chartToolbarExpander;
private List _comparisonGoodsList;
private DateTime _crossDateTime;
///
/// 十字光标鼠标按下状态
///
private bool _crossFlag;
//十字光标容器
private Canvas _crossHairGrid;
private Path _crossPath;
private Line _hline = new Line(); //横线
private Line _vline = new Line(); //竖线
///
/// 十字光标面板x坐标
///
private double _crossX;
private IDrawingTool _currentDrawingTool;
private double _currentX;
private double _currentY;
//数据滑块容器
private StackPanel _dateChartSliderStackPanel;
private DateScaleDisplay _dateScaleDisplay;
private Button _downloadMoreButton;
private TextBlock _downloadMoreButtonPlaceHolder;
private ChartDrawingToolbar _drawingToolbar;
//画线工具容器
private StackPanel _drawingToolStackPanel;
//商品信息
private GoodsInfo _goodsInfo;
///指标器容器
//private ComboBox _indicatorComboBox;
public Grid _mainGrid;
private BusyIndicator _exportBusyIndicator;
///
/// 上一个鼠标样式
///
private PointerType _oldPointerType;
private Grid _pointerGrid;
private Popup _pointerPopup;
///
/// 当前鼠标样式,初始为显示十字光标
///
private PointerType _pointerType;
private Popup _popup;
///
/// The timespan control
///
private QuickTimeSpan _timeSpanControl;
//显示标签控件
//private TextBlock _symbolTextBlock;
private Image _toolImage;
///
/// 当前图中添加图表容器
///
private List _chartPanes = new List();
private DispatcherTimer _timeSharingTimer;
private DisplayFormula timeSharingFormulaModel; //分时图实体,用于更新当前分时图数据
private DisplayFormula _tikFormulaModel; //即时图,更新Tik图表数据
private DisplayFormula _minuteFormulaModel; //
private Dictionary _comparisonFommulaHsSet = new Dictionary();
private List _chartCachePanes = new List(); //缓存切换周期时商品状态
private static readonly object _lockObject = new Object();
#endregion Fields
#region Constructors
///
/// 静态构造函数
///
static Chart()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(Chart), new FrameworkPropertyMetadata(typeof(Chart)));
}
///
/// 构造函数
///
public Chart()
{
this.Focusable = true;
//默认加载简体中文
LanguageManager.SetLanguage(CultureInfo.InstalledUICulture.Name);
_dateScaleDisplay = new DateScaleDisplay(this);
DateScaler = new AllDateScaler(this);
_toolImage = new Image();
DateChartSlider = new DateChartSlider(this);
TimeSpanPicker = new QuickTimeSpan(this);
RightBuffer = 0;
//ChartRedrawTimer.Interval = new TimeSpan(0, 0, 0, 0, ChartRedrawSpeed);
_oldDrawingTool = new DrawingTrendLine();
_pointerType = PointerType.CursorWithData;
_oldPointerType = PointerType.CursorWithData;
LockPainting = false;
ComparisionDictionary = new Dictionary>();
_timeSharingTimer = new DispatcherTimer();
_timeSharingTimer.Interval = new TimeSpan(0, 0, 1, 0);
_timeSharingTimer.Tick += _timeSharingTimer_Tick;
ComparisionTimeShareDic = new Dictionary>();
}
#endregion Constructors
#region Properties
#region Public Properties
///
/// ChartRedrawSpeed,图表重绘速度,用于鼠标拖动,画图工具拖动等,单位为毫秒
///
public int ChartRedrawSpeed = 1000 / 30;
///
/// ChartRedrawTimer,图表重绘定时器
///
DispatcherTimer ChartRedrawTimer = new DispatcherTimer();
private const string _defaoltIndecator = "EMA4,MACD";
private DateTime _goodsQuoteTime; //分时图行情时间
///
/// 左右键增减周期值
///
public int LeftRightKeyToAcceleration
{
get { return (int)GetValue(LeftRightKeyToAccelerationProperty); }
set { SetValue(LeftRightKeyToAccelerationProperty, value); }
}
///
/// 加速因数
///
public int AcceleratedWheelFactor
{
get
{
return (int)base.GetValue(Chart.AcceleratedWheelFactorProperty);
}
set
{
base.SetValue(Chart.AcceleratedWheelFactorProperty, value);
}
}
///
/// 加速鼠标中键缩放键
///
public ModifierKeys AcceleratedWheelModifierKeys
{
get
{
return (ModifierKeys)base.GetValue(Chart.AcceleratedWheelModifierKeysProperty);
}
set
{
base.SetValue(Chart.AcceleratedWheelModifierKeysProperty, value);
}
}
///
/// 获取或设置一个用于描述控件背景的画笔。
///
public SolidColorBrush ChartBackground
{
get
{
return (SolidColorBrush)base.GetValue(Chart.ChartBackgroundProperty);
}
set
{
base.SetValue(Chart.ChartBackgroundProperty, value);
}
}
///
/// Gets the color of the chart background.
///
public Color ChartBackgroundColor
{
get
{
return ColorHelper.ColorFromBrush(ChartBackground);
}
}
///
/// 获取或设置字号。
///
public double ChartFontSize
{
get
{
var value = (double)base.GetValue(Chart.ChartFontSizeProperty);
if (value <= 0) value = 12;
return value;
}
set
{
if (value <= 0) value = 12;
base.SetValue(Chart.ChartFontSizeProperty, value);
}
}
///
/// 图表语言类型
///
public ChartLanguageType ChartLanguage
{
get
{
return (ChartLanguageType)base.GetValue(Chart.ChartLanguageProperty);
}
set
{
base.SetValue(Chart.ChartLanguageProperty, value);
}
}
///
/// Gets or sets the chart time span.
///
/// The chart time span.
public TimeSpan ChartTimeSpan
{
get { return (TimeSpan)GetValue(ChartTimeSpanProperty); }
set { SetValue(ChartTimeSpanProperty, value); }
}
public IDrawingTool CurrentDrawingTool
{
get
{
return _currentDrawingTool;
}
set
{
_currentDrawingTool = value;
bool flag = value != null;
if (flag)
{
PointerType = PointerType.Drawing;
}
}
}
/////
///// 商品信息
////
public GoodsInfo CurrentGoods
{
get { return (GoodsInfo)GetValue(CurrentGoodsProperty); }
set { SetValue(CurrentGoodsProperty, value); }
}
///
/// 商品周期
///
public List CycleItems
{
get { return (List)GetValue(CycleItemsProperty); }
set { SetValue(CycleItemsProperty, value); }
}
///
/// 根据周期生成TimeSpan
///
public TimeSpan CurrentTimeFrame
{
get
{
switch (CycleType)
{
case CycleType.Minute:
return new TimeSpan(0, 1, 0);
case CycleType.Minute3:
return new TimeSpan(0, 3, 0);
case CycleType.Minute5:
return new TimeSpan(0, 5, 0);
case CycleType.Minute10:
return new TimeSpan(0, 10, 0);
case CycleType.Minute15:
return new TimeSpan(0, 15, 0);
case CycleType.Minute30:
return new TimeSpan(0, 30, 0);
case CycleType.Minute60:
return new TimeSpan(1, 0, 0);
case CycleType.Minute90:
return new TimeSpan(1, 30, 0);
case CycleType.Minute120:
return new TimeSpan(2, 0, 0);
case CycleType.Minute180:
return new TimeSpan(3, 0, 0);
case CycleType.Minute240:
return new TimeSpan(4, 0, 0);
case CycleType.Hour:
return new TimeSpan(1, 0, 0);
case CycleType.Day:
return new TimeSpan(1, 0, 0, 0);
case CycleType.Week:
return new TimeSpan(7, 0, 0, 0, 0);
case CycleType.Month:
return new TimeSpan(30, 0, 0, 0);
case CycleType.Quarter:
return new TimeSpan(90, 0, 0, 0);
case CycleType.Year:
return new TimeSpan(255, 0, 0, 0);
case CycleType.Custom:
return ChartTimeSpan;
default:
//分时图为1分
return new TimeSpan(0, 1, 0);
}
}
}
///
/// 是否在周期内
///
public bool IsNotInCycle(DateTime tikTime, ref DateTime CycleDate)
{
var Rlt = default(bool);
if (DataSet != null && DataSet.DataPoints != null && DataSet.DataPoints.Count() > 0 && tikTime != DateTime.MinValue)
{
var dt = DataSet.DataPoints.Last().Date;
var ts = tikTime - dt;
var newDt = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0).AddMinutes(CurrentTimeFrame.TotalMinutes);
switch (CycleType)
{
case CycleType.Minute:
case CycleType.Minute3:
case CycleType.Minute5:
case CycleType.Minute10:
case CycleType.Minute15:
case CycleType.Minute30:
case CycleType.Minute60:
case CycleType.Minute90:
case CycleType.Minute120:
case CycleType.Minute180:
case CycleType.Minute240:
case CycleType.Custom:
case CycleType.Hour:
Rlt = tikTime >= newDt;
if (Rlt)
{
CycleDate = new DateTime(dt.Year, dt.Month, dt.Day, dt.Hour, dt.Minute, 0).AddMinutes((Math.Floor((ts.TotalMinutes / CurrentTimeFrame.TotalMinutes)) * CurrentTimeFrame.TotalMinutes));
}
break;
case CycleType.Day:
Rlt = tikTime >= new DateTime(dt.Year, dt.Month, dt.Day ).AddDays(1);
if (Rlt)
{
CycleDate = new DateTime(dt.Year, dt.Month, dt.Day).AddDays((Math.Floor((ts.TotalDays / CurrentTimeFrame.TotalDays)) * CurrentTimeFrame.TotalDays));
}
break;
case CycleType.Week:
Rlt = tikTime >= new DateTime(dt.Year, dt.Month, dt.Day ).AddDays((7 - ((int)(DayOfWeek)dt.DayOfWeek)));
if (Rlt)
{
CycleDate = new DateTime(dt.Year, dt.Month, dt.Day).AddDays((Math.Floor((ts.TotalDays / CurrentTimeFrame.TotalDays)) * CurrentTimeFrame.TotalDays));
}
break;
case CycleType.Month:
Rlt = tikTime >= new DateTime(dt.Year, dt.Month , 1).AddMonths(1);
if (Rlt)
{
CycleDate = new DateTime(dt.Year, tikTime.Month, 1);
}
break;
case CycleType.Quarter:
Rlt = tikTime >= new DateTime(dt.Year, dt.Month , 1).AddMonths(3);
if (Rlt)
{
var mm = (Math.Floor((ts.TotalDays / CurrentTimeFrame.TotalDays)) * CurrentTimeFrame.TotalDays);
CycleDate = new DateTime(dt.Year, dt.Month, 1).AddDays(mm);
}
break;
case CycleType.Year:
Rlt = tikTime >= new DateTime(dt.Year + 1, 1, 1);
if (Rlt)
{
CycleDate = new DateTime(tikTime.Year, 1, 1);
}
break;
default:
Rlt = false;
break;
}
//Console.WriteLine("time:{0} tikTime:{1} newdate Rlt:{2} RltTime:{3}", dt.ToString(), tikTime.ToString(), newDt.ToString(), Rlt.ToString(), CycleDate.ToString());
}
return Rlt;
}
///
/// 商品周期
///
public CycleType CycleType
{
get
{
return (CycleType)base.GetValue(Chart.CycleTypeProperty);
}
set
{
if (value != CycleType.Custom)
{
ChartTimeSpan = default(TimeSpan);
}
base.SetValue(Chart.CycleTypeProperty, value);
}
}
///
/// 数据滑块
///
public DateChartSlider DateChartSlider
{
get;
set;
}
///
/// Gets the drawing min chart span percent.
///
public float DrawingMinChartSpanPercent
{
get
{
return 5f;
}
}
///
/// 画线工具位置
///
public DrawingToolPositionType DrawingToolPosition
{
get
{
return (DrawingToolPositionType)base.GetValue(Chart.DrawingToolPositionProperty);
}
set
{
base.SetValue(Chart.DrawingToolPositionProperty, value);
}
}
///
/// 当前画线工具
///
public DrawingToolType DrawingToolType
{
get
{
return (DrawingToolType)base.GetValue(Chart.DrawingToolTypeProperty);
}
set
{
base.SetValue(Chart.DrawingToolTypeProperty, value);
}
}
///
/// 蜡烛图叠加是否填充
///
public bool FillComparisonCandle
{
get { return (bool)GetValue(FillComparisonCandleProperty); }
set { SetValue(FillComparisonCandleProperty, value); }
}
///
/// 获取或设置一个用于描述控件背景的画笔。
///
public double GridOpacity
{
get
{
return (double)base.GetValue(Chart.GridOpacityProperty);
}
set
{
base.SetValue(Chart.GridOpacityProperty, value);
}
}
///
/// Gets a value indicating whether this instance is dark background.
///
public bool IsDarkBackground
{
get
{
var brush = ChartBackground as SolidColorBrush;
if (brush != null)
{
return ColorHelper.ColorIsDark(brush.Color);
}
return false;
}
}
///
/// Gets a value indicating whether [limit drawings by span].
///
public bool LimitDrawingsBySpan
{
get
{
return true;
}
}
///
/// 获取或设置一个用于描述控件背景的画笔。
///
public LinePlotType LinePlotType
{
get
{
return (LinePlotType)base.GetValue(Chart.LinePlotTypeProperty);
}
set
{
base.SetValue(Chart.LinePlotTypeProperty, value);
}
}
///
/// 最大加载数据条数
///
public int MaxLoadRecordCount
{
get { return (int)GetValue(MaxLoadRecordCountProperty); }
set { SetValue(MaxLoadRecordCountProperty, value); }
}
///
/// 最大条数
///
public int MaxRecordCount
{
get
{
return (int)base.GetValue(Chart.MaxRecordCountProperty);
}
set
{
base.SetValue(Chart.MaxRecordCountProperty, value);
}
}
///
/// 最小条数
///
public int MinRecordCount
{
get
{
return (int)base.GetValue(Chart.MinRecordCountProperty);
}
set
{
base.SetValue(Chart.MinRecordCountProperty, value);
}
}
///
/// 返回叠加商品
///
public List ComparisonGoodsList
{
get
{
return _comparisonGoodsList;
}
}
///
/// 分时图使用的显示最大点数据,根据开收盘时间计算
///
private int _timeSharingMaxPointCount = 60;
internal int MaxRecordCountInternal
{
get
{
if (CycleType == CycleType.TimeSharing)
{
return _timeSharingMaxPointCount;
}
else
{
return MaxRecordCount;
}
}
}
internal int MinRecordCountInternal
{
get
{
if (CycleType == CycleType.TimeSharing)
{
return _timeSharingMaxPointCount;
}
else
{
return MinRecordCount;
}
}
}
internal int RecordCountInternal
{
get
{
if (CycleType == CycleType.TimeSharing)
{
return _timeSharingMaxPointCount;
}
else
{
return RecordCount;
}
}
}
///
/// Gets or sets the type of the pointer.
///
/// The type of the pointer.
public PointerType PointerType
{
get
{
return _pointerType;
}
set
{
bool flag = value != _pointerType;
if (flag)
{
bool flag2 = value != PointerType.Drawing && value != PointerType.Erase;
if (flag2)
{
_oldPointerType = value;
}
_pointerType = value;
flag2 = (_pointerType != PointerType.Drawing);
if (flag2)
{
CurrentDrawingTool = null;
}
}
}
}
///
/// 显示数据条数
///
public int RecordCount
{
get
{
return (int)base.GetValue(Chart.RecordCountProperty);
}
set
{
base.SetValue(Chart.RecordCountProperty, value);
}
}
///
/// Gets or sets the show drawing tool.
///
public Visibility ShowDrawingTool
{
get
{
return (Visibility)base.GetValue(Chart.ShowDrawingToolProperty);
}
set
{
base.SetValue(Chart.ShowDrawingToolProperty, value);
}
}
///
/// Gets or sets a value indicating whether [show legend arrows].
///
public bool ShowLegendArrows
{
get;
set;
}
///
/// Gets or sets the time span picker.
///
public QuickTimeSpan TimeSpanPicker
{
get
{
return _timeSpanControl;
}
set
{
_timeSpanControl = value;
}
}
#endregion Public Properties
#region Internal Properties
///
/// 叠加商品字典
///
internal Dictionary> ComparisionDictionary
{
get;
set;
}
///
/// 分时图商品字典
///
internal Dictionary> ComparisionTimeShareDic
{
get;
set;
}
///
/// Gets the current symbol.
///
internal string CurrentSymbol
{
get
{
var goods = CurrentGoods;
if (goods == null || string.IsNullOrWhiteSpace(goods.Symbol)) return string.Empty;
return goods.Symbol;
}
}
///
/// 数据集
///
internal ChartDataSet DataSet
{
get;
set;
}
///
/// Gets or sets the date scaler.
///
internal IDateScaler DateScaler
{
get;
set;
}
private int _offSetNum = 0;
///
/// Gets or sets a value indicating whether [lock painting].
///
internal bool LockPainting
{
get;
set;
}
///
/// 是否为分时图,控制部分内容不显示
///
//internal bool IsTimeShare
//{
// get;
// set;
//}
#endregion Internal Properties
#endregion Properties
#region Methods
#region Public Methods
///
/// 添加指标窗口
///
public void AddIndicator()
{
//todo:
//var formula = new FormulaModel();
//formula.FormulaName = indicatorType;
//var displayFormula = new DisplayFormula(formula, DataSet, this);
// AddPlot(displayFormula, null);
var listPlots = DisplayFormula.CreateDisplayFormula(DataSet, this);
if (listPlots != null)
{
ChartPane pane = null;
foreach (var displayFormula in listPlots)
{
pane = AddFormula(displayFormula, false, pane);
}
}
Refresh(true);
}
///
/// 清除叠加商品
///
public void ClearComparison()
{
if (_comparisonGoodsList != null) _comparisonGoodsList.Clear();
if ((ComparisionDictionary == null || !ComparisionDictionary.Any()) &&
(ComparisionTimeShareDic == null || !ComparisionTimeShareDic.Any())) return;
ComparisionDictionary.Clear();
var mainScalelayer = GetMainScaleLayer();
if (mainScalelayer == null) return;
var plots = mainScalelayer.AllPlots.Where(z => z is ComparisonPlot);
if (plots == null || !plots.Any()) return;
var comparsions = plots.ToList();
foreach (var comparison in comparsions)
{
comparison.Delete();
}
mainScalelayer.ComparisonFormulas.Clear();
//清除分时图叠加
if (ComparisionTimeShareDic != null && ComparisionTimeShareDic.Any())
{
ComparisionTimeShareDic.Clear();
}
if (_comparisonFommulaHsSet != null && _comparisonFommulaHsSet.Any())
{
_comparisonFommulaHsSet.Clear();
}
if (timeSharingFormulaModel != null)
{
var compesionsPlots = timeSharingFormulaModel.ScaleLayer.AllPlots.Where(z => z is ComparisonPlot);
if (compesionsPlots.Any()) return;
comparsions = compesionsPlots.ToList();
foreach (var comparison in comparsions)
{
comparison.Delete();
}
}
Refresh();
}
///
/// 在派生类中重写后,每当应用程序代码或内部进程调用 ,都将调用此方法。
///
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
try
{
BuildParts();
//初始化画图工具栏
InitializeDrawingTool();
//添加历史价格图和成交量图
AddDefaultIndicators();
//添加图表底部控件
BuildBottomControls();
}
catch { ;}
}
///
/// 设置叠加商品
///
/// The goods list.
public void SetComparisonGoodsList(List goodsList)
{
Dispatcher.BeginInvoke(new Action(() =>
{
if (goodsList == null || !goodsList.Any()) return;
ClearComparison();
if (this.CycleType == CycleType.TimeSharing)
{
foreach (var goods in goodsList)
{
AddComparisonFormula(null, null, goods);
}
_comparisonGoodsList = goodsList;
Refresh(true);
return;
}
//Clear里有清空变量,放在后面
_comparisonGoodsList = goodsList;
var chartPane = GetMainChartPane(); //要叠加的容器
foreach (var goods in goodsList)
{
//不叠加空和自己
if (goods == null || string.IsNullOrWhiteSpace(goods.Symbol) ||
string.CompareOrdinal(goods.Symbol, CurrentSymbol) == 0) continue;
var dataPoints = LoadComparisonDataSet(goods);
if (dataPoints == null) continue;
ComparisionDictionary.Add(goods.Symbol, dataPoints);
//添加叠加商品
if (chartPane != null)
{
AddComparisonFormula(new ChartDataSet(dataPoints), chartPane, goods);
}
}
Refresh(true);
}), DispatcherPriority.Background);
}
///
/// 更新数据集合-行情组件取服务数据回发时调用
///
/// The points.
public void UpdateDataPoints(IEnumerable points)
{
Task.Factory.StartNew(new Action(() =>
{
var lineDataPoints = points == null ? null : points.ToList();
if (lineDataPoints == null || !lineDataPoints.Any()) return;
DataSet = DataSet ?? new ChartDataSet();
//集合都要按时间顺排序,才能画图
var oldDataPoints = DataSet.DataPoints ?? new List();
var totalDataPoints = lineDataPoints.Union(oldDataPoints, new DataPointComparer());
DataSet.DataPoints = CaclulateCycleDataIncrease(totalDataPoints.OrderBy(z => z.Date).ToList());
Dispatcher.BeginInvoke(new Action(() =>
{
var allDateScaler = (AllDateScaler)DateScaler;
allDateScaler.SetDates(DataSet.DataPoints, CurrentTimeFrame, false);
Refresh(true);
//刷新叠加商品
RefreshComparsionGoods();
}), DispatcherPriority.Background);
}));
}
///
/// 更新数据集合-行情组件取服务数据回发时调用
///
/// The points.
public void UpdateTimeSharingDataPoints(IEnumerable points)
{
Dispatcher.BeginInvoke(new Action(() =>
{
var lineDataPoints = points == null ? null : points.ToList();
if (lineDataPoints == null || !lineDataPoints.Any()) return;
DataSet = DataSet ?? new ChartDataSet();
//集合都要按时间顺排序,才能画图
DataSet.DataPoints = points.OrderBy(z => z.Date).ToList();
if (timeSharingFormulaModel == null) return;
{
timeSharingFormulaModel.UpdateTimeSharingData(DataSet);
}
Refresh(true);
}), DispatcherPriority.Background);
}
///
/// 更新叠加商品数据集合
///
/// The comparison symbol.
/// The points.
public void UpdateComparisonDataPoints(string comparisonSymbol, IEnumerable points)
{
Dispatcher.BeginInvoke(new Action(() =>
{
if (_comparisonGoodsList == null || !_comparisonGoodsList.Any()) return;
var comparisonGoods = _comparisonGoodsList.FirstOrDefault(z => z.Symbol == comparisonSymbol);
if (comparisonGoods == null) return;
//集合都要按时间顺排序,才能画图
var dataPoints = points ?? new List();
var oldDataPoints = ComparisionDictionary[comparisonSymbol] ?? new List();
var totalDataPoints =
dataPoints.Union(oldDataPoints, new DataPointComparer())
.OrderBy(z => z.Date)
.ToList();
//目前只能一个商品叠加,更新的时候清除所有
var list = new List();
list.AddRange(_comparisonGoodsList);
#region 商品叠加
ClearComparison();
_comparisonGoodsList = list;
ComparisionDictionary.Add(comparisonSymbol, totalDataPoints);
var disPlayFormula = new DisplayFormula(new FormulaModel("main"), new ChartDataSet(totalDataPoints), this, comparisonGoods);
var scaleLayer = GetMainScaleLayer();
if (scaleLayer == null) return;
disPlayFormula.PlotBases.Clear();
scaleLayer.ComparisonFormulas.Clear();
foreach (var indicator in disPlayFormula.FormulaModel.IndicatorList)
{
var comparisonPlot = new ComparisonPlot(indicator, this, comparisonGoods)
{
IsActive = true,
ScaleLayer = scaleLayer
};
scaleLayer.AllPlots.Add(comparisonPlot);
disPlayFormula.PlotBases.Add(comparisonPlot); //添加到公式中
}
scaleLayer.ComparisonFormulas.Add(disPlayFormula);
disPlayFormula.ScaleLayer = scaleLayer;
#endregion
Refresh(true);
}), DispatcherPriority.Background);
}
///
/// 导出数据到Excel
///
public void ExportToExcel()
{
//正在下载数据则返回
if (_exportBusyIndicator.IsBusy) return;
if (this.CurrentGoods == null) return;
if (this.DataSet == null || this.DataSet.DataPoints == null || !this.DataSet.DataPoints.Any()) return;
var width = this.ActualWidth;
this.Width = width;
var displayName = string.IsNullOrWhiteSpace(this.CurrentGoods.DisplayName)
? this.CurrentGoods.GoodsCode
: this.CurrentGoods.DisplayName;
var exportHelper = new ExportHelper();
exportHelper.OnStartExport += OnStartExport;
exportHelper.OnExportCompleted += OnExportCompleted;
exportHelper.ExportToExcel(displayName, CycleType, this.DataSet.DataPoints, this.CurrentGoods.MinUnit);
}
///
/// 数据导出开始
///
/// The sender.
/// The instance containing the event data.
private void OnStartExport(object sender, EventArgs e)
{
//要在SaveFileDiaolog关闭后再启动BusyIndicator,否则界面会有SaveFileDiaolog窗口的黑影
_exportBusyIndicator.IsBusy = true;
}
///
/// 数据导出完成
///
/// The message.
/// The caption.
private void OnExportCompleted(string message, string caption)
{
_exportBusyIndicator.IsBusy = false;
//message为空,只不弹出信息
if (string.IsNullOrWhiteSpace(message)) return;
System.Windows.MessageBox.Show(Application.Current.MainWindow, message, caption);
}
#endregion Public Methods
#region Internal Methods
///
/// sts.
///
/// The parent.
/// The indicator model.
/// if set to true [allow defaults].
/// PlotBase.
internal PlotBase AddChildPlot(LinePlot parent, IndicatorModel indicatorModel, bool AllowDefaults)
{
ScaleLayer scaleLayer = parent.ScaleLayer;
bool flag = scaleLayer != null;
PlotBase result = null;
if (flag)
{
//bool flag2 = aCalc is ILineCalculation;
//if (flag2)
//{
var linePlot = new LinePlot(indicatorModel, parent.GetChart());
//flag2 = (aCalc is calcVolumeAtPrice);
//if (flag2)
//{
// linePlot.PlotOpacity = ((calcVolumeAtPrice)aCalc).DefaultOpacity();
//}
linePlot.InitAsNew();
//if (AllowDefaults)
//{
// WebChart_5948(linePlot);
//}
// scaleLayer.AddPlot(linePlot);
linePlot.ScaleLayer = scaleLayer;
result = linePlot;
//}
//else
//{
//flag2 = (aCalc is IChannelCalc);
//if (flag2)
//{
// ChannelPlot channelPlot = new ChannelPlot(parent.LinePlot_4866(), (IChannelCalc)aCalc);
// channelPlot.InitAsNew();
// if (AllowDefaults)
// {
// WebChart_5948(channelPlot);
// }
// scaleLayer.ScaleLayer_5530(channelPlot);
// channelPlot.ScaleLayer = scaleLayer;
// WebChart_2077 = true;
// result = channelPlot;
//}
//else
//{
// flag2 = (aCalc is ITwoLineCalc);
// if (flag2)
// {
// TwoLinePlot twoLinePlot = new TwoLinePlot(parent.LinePlot_4866(), (ITwoLineCalc)aCalc);
// twoLinePlot.InitAsNew();
// if (AllowDefaults)
// {
// WebChart_5948(twoLinePlot);
// }
// scaleLayer.ScaleLayer_5530(twoLinePlot);
// twoLinePlot.ScaleLayer = scaleLayer;
// WebChart_2077 = true;
// result = twoLinePlot;
// }
//}
//}
}
return result;
}
///
/// 添加叠加商品
///
public void AddComparisonFormula(ILineDataSet dataSet, ChartPane addToPane, GoodsInfo goodsInfo)
{
if (this.CycleType == CycleType.TimeSharing && this.timeSharingFormulaModel != null)
{
if (goodsInfo == null || goodsInfo.GoodsCode == this.CurrentGoods.GoodsCode ||
ComparisionTimeShareDic.ContainsKey(goodsInfo.GoodsCode)) return;
var dataList = OnLoadHistoryTimeSpaningCycleData(CurrentGoods, _timeSharingMaxPointCount, timeSharingFormulaModel.OpenTime,
timeSharingFormulaModel.CloseTime);
var diplayformula = DisplayFormula.TimeSharingLineFormula(this, goodsInfo, dataList);
ComparisionTimeShareDic[goodsInfo.GoodsCode] = dataList;
CreateComparisonPlot(diplayformula, this.timeSharingFormulaModel.ScaleLayer);
}
else
{
var disPlayFormula = new DisplayFormula(new FormulaModel("main"), dataSet, this, goodsInfo);
ChartPane pane = addToPane;
bool flag = addToPane == null;
if (flag)
{
pane = new ChartPane(this);
}
flag = (addToPane == null);
if (flag)
{
//取最大grid高度做*
var stars = _chartPanesGrid.RowDefinitions.Count > 0 ? _chartPanesGrid.RowDefinitions.Max(z => z.Height.Value) : 1.0;
AddChartPane(pane, stars);
}
var scaleLayer = GetMainScaleLayer();
if (scaleLayer == null) return;
disPlayFormula.PlotBases.Clear();
scaleLayer.ComparisonFormulas.Clear();
foreach (var indicator in disPlayFormula.FormulaModel.IndicatorList)
{
var comparisonPlot = new ComparisonPlot(indicator, this, goodsInfo);
comparisonPlot.IsActive = true;
comparisonPlot.ScaleLayer = scaleLayer;
scaleLayer.AllPlots.Add(comparisonPlot);
disPlayFormula.PlotBases.Add(comparisonPlot); //添加到公式中
}
scaleLayer.ComparisonFormulas.Add(disPlayFormula);
disPlayFormula.ScaleLayer = scaleLayer;
}
}
///
/// 移除叠加商品
///
public void RemoveComparisonForLuma()
{
}
///
/// 添加图例
///
///
///
internal void AddPlot(DisplayFormula formula, PlotBase childTarget)
{
bool flag = formula == null;
if (!flag)
{
flag = (childTarget != null && childTarget.ScaleLayer != null &&
childTarget.ScaleLayer.GetChartPane() != null);
if (flag)
{
var addToPane = childTarget.ScaleLayer.GetChartPane();
AddFormula(formula, true, addToPane);
}
else
{
AddFormula(formula, true);
}
}
}
internal List AllPanes()
{
var list = new List();
if (_chartPanesGrid == null || _chartPanesGrid.Children == null || _chartPanesGrid.Children.Count == 0)
return list;
list.AddRange(_chartPanesGrid.Children.OfType());
return list;
}
///
/// 下载前N条数据(N = MaxLoadRecordCount)
///
internal void DownloadNextDataBlock()
{
var goods = CurrentGoods;
var exchangeCode = CurrentGoods.ExchangeCode;
var goodsCode = CurrentGoods.GoodsCode;
var cycleType = CycleType;
var timeSpan = CurrentTimeFrame;
var maxLoadRecordCount = MaxLoadRecordCount;
Task.Factory.StartNew(new Action(() =>
{
//数据集有值,取最小时间, 无值,取当前时间
var maxTime = (DataSet != null && DataSet.DataPoints != null && DataSet.DataPoints.Any())
? DataSet.DataPoints.Min(z => z.Date)
: DateTime.Now;
//减去周期ticks,作为当前下载最大值
maxTime = maxTime.AddTicks(-timeSpan.Ticks);
if (DataSet == null)
{
DataSet = new ChartDataSet();
}
List newData = null;
var cycleTypeHandler = LoadHistoryCycleDataByCycleType;
if (cycleTypeHandler != null)
{
newData = cycleTypeHandler(exchangeCode, goodsCode, cycleType,
timeSpan, DateTime.MinValue, maxTime, maxLoadRecordCount);
}
var dataPoints = new List();
if (newData != null && newData.Any())
{
dataPoints.AddRange(CaclulateCycleDataIncrease(newData));
if (DataSet.DataPoints != null && dataPoints.Any())
{
//只更新前面数据块第一条数据涨幅
var firstOld = DataSet.DataPoints[0] as IOHLCDataPoint;
var lastNew = newData[newData.Count - 1] as IOHLCDataPoint;
if (firstOld != null && lastNew != null)
{
firstOld.Increase = lastNew.Close.Equals(0)
? 0f
: (firstOld.Close - lastNew.Close) / lastNew.Close;
firstOld.IncreaseValue = lastNew.Close.Equals(0) ? 0f : (firstOld.Close - lastNew.Close);
}
dataPoints.AddRange(DataSet.DataPoints);
}
DataSet.DataPoints = dataPoints.OrderBy(z => z.Date).ToList();
Dispatcher.BeginInvoke(new Action(() =>
{
var allDateScaler = (AllDateScaler)DateScaler;
allDateScaler.SetDates(DataSet.DataPoints, timeSpan, false);
//前一数据块的最后时间做为当前的结束时间
allDateScaler.DesiredEndDate = maxTime.AddTicks(timeSpan.Ticks);
Refresh(true);
//刷新叠加商品
RefreshComparsionGoods();
}), DispatcherPriority.Background);
}
}));
}
///
/// 若画图则隐藏十字光标
///
internal void DrawingToolExecute()
{
if (PointerType != PointerType.Drawing)
{
if (_crossHairGrid.Visibility == Visibility.Collapsed)
{
_crossHairGrid.Visibility = Visibility.Visible;
}
//TODO:更改所有控件的背景颜色
var panes = AllPanes();
foreach (var chartPane in panes)
{
chartPane.OnDrawing();
}
}
else
{
if (_crossHairGrid.Visibility == Visibility.Visible)
{
_crossHairGrid.Visibility = Visibility.Collapsed;
}
}
}
internal double GetChartPanelOffset()
{
return _chartPanesGrid.ColumnDefinitions[0].ActualWidth;
}
///
/// 得到的图表窗格的宽度.
///
/// System.Double.
internal double GetChartPaneWidth()
{
//0:左纵坐标, 1:Chart, 2:右纵坐标
return Math.Round(_chartPanesGrid.ColumnDefinitions[1].ActualWidth) - RightBuffer;
}
///
/// 获取当前已打开的主图LinePlot
///
/// PlotBase.
internal T GetPlot(string formulaName) where T : PlotBase
{
var panes = AllPanes();
if (panes == null || !panes.Any()) return default(T);
var name = formulaName.ToLower();
foreach (var chartPane in panes)
{
var scaleLayers = chartPane.AllScaleLayers;
if (scaleLayers == null || !scaleLayers.Any()) continue;
foreach (var scaleLayer in scaleLayers)
{
var plots = scaleLayer.AllPlots;
if (plots == null || !plots.Any()) continue;
foreach (var plot in plots)
{
if (plot != null && (plot is T) && plot.Indicator.ParentFormula.FormulaName.ToLower() == name) return plot as T;
}
}
}
return null;
}
private ScaleLayer GetMainScaleLayer()
{
var panes = AllPanes();
if (panes == null || !panes.Any()) return null;
foreach (var chartPane in panes)
{
var scaleLayers = chartPane.AllScaleLayers;
if (scaleLayers == null || !scaleLayers.Any()) continue;
foreach (var scaleLayer in scaleLayers)
{
var formulas = scaleLayer.AllDisplayFormula;
if (formulas == null || !formulas.Any()) continue;
foreach (var formula in formulas)
{
if (formula != null && formula.FormulaModel.IsMain)
{
return scaleLayer;
}
}
}
}
return null;
}
///
/// 初始化画图工具栏
///
internal void InitializeDrawingTool()
{
if (_drawingToolStackPanel == null) return;
if (_drawingToolbar == null) _drawingToolbar = new ChartDrawingToolbar(this);
if (_chartToolbarExpander == null) _chartToolbarExpander = new ChartToolbarExpander(_drawingToolbar);
//隐藏画线工具展开按钮
_chartToolbarExpander.Visibility = Visibility.Hidden;
switch (DrawingToolPosition)
{
case DrawingToolPositionType.Left:
_drawingToolStackPanel.SetValue(Grid.RowProperty, 0);
_drawingToolStackPanel.SetValue(Grid.RowSpanProperty, 4);
_drawingToolStackPanel.SetValue(Grid.ColumnProperty, 0);
_drawingToolStackPanel.Orientation = Orientation.Vertical;
_drawingToolStackPanel.HorizontalAlignment = HorizontalAlignment.Left;
_drawingToolbar.UpdateLayout(Orientation.Vertical);
break;
case DrawingToolPositionType.Right:
_drawingToolStackPanel.SetValue(Grid.RowProperty, 0);
_drawingToolStackPanel.SetValue(Grid.RowSpanProperty, 4);
_drawingToolStackPanel.SetValue(Grid.ColumnProperty, 2);
_drawingToolStackPanel.Orientation = Orientation.Vertical;
_drawingToolStackPanel.HorizontalAlignment = HorizontalAlignment.Right;
_drawingToolbar.UpdateLayout(Orientation.Vertical);
break;
case DrawingToolPositionType.Top:
_drawingToolStackPanel.SetValue(Grid.RowProperty, 1);
_drawingToolStackPanel.SetValue(Grid.RowSpanProperty, 1);
_drawingToolStackPanel.SetValue(Grid.ColumnProperty, 1);
_drawingToolStackPanel.Orientation = Orientation.Horizontal;
_drawingToolStackPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
_chartToolbarExpander.VerticalAlignment = VerticalAlignment.Top;
_drawingToolbar.UpdateLayout(Orientation.Horizontal);
break;
case DrawingToolPositionType.Bottom:
_drawingToolStackPanel.SetValue(Grid.RowProperty, 3);
_drawingToolStackPanel.SetValue(Grid.RowSpanProperty, 1);
_drawingToolStackPanel.SetValue(Grid.ColumnProperty, 1);
_drawingToolStackPanel.Orientation = Orientation.Horizontal;
_drawingToolStackPanel.HorizontalAlignment = HorizontalAlignment.Stretch;
_chartToolbarExpander.VerticalAlignment = VerticalAlignment.Top;
_drawingToolbar.UpdateLayout(Orientation.Horizontal);
break;
}
if (!_drawingToolStackPanel.Children.Contains(_chartToolbarExpander))
_drawingToolStackPanel.Children.Add(_chartToolbarExpander);
if (!_drawingToolStackPanel.Children.Contains(_drawingToolbar))
_drawingToolStackPanel.Children.Add(_drawingToolbar);
}
private int i = 0;
private double currentX = 0;
private double currentY = 0;
///
/// 刷新图表
///
/// if set to true [is updata set].
internal void Refresh(bool isUpdataSet = false)
{
lock (_lockObject)
{
if (!LockPainting)
{
Dispatcher.BeginInvoke(new Action(DrawingChart), DispatcherPriority.Background, isUpdataSet);
}
}
}
internal void RemoveChartPane(ChartPane aPane)
{
int num = Conversions.ToInteger(aPane.GetValue(Grid.RowProperty));
_chartPanesGrid.Children.Remove(aPane);
_chartPanes.Remove(aPane);
if (aPane.RightScaleControl != null)
{
_chartPanesGrid.Children.Remove(aPane.RightScaleControl);
}
if (aPane.LeftScaleControl != null)
{
_chartPanesGrid.Children.Remove(aPane.LeftScaleControl);
}
_chartPanesGrid.RowDefinitions.RemoveAt(num);
UIElement currentSplitter = null;
foreach (var uiElement in _chartPanesGrid.Children)
{
var current = uiElement as UIElement;
if (current != null &&
(current is ChartPane || current is ValueScaleDisplayCollection || current is GridSplitter))
{
int rowIndex = Conversions.ToInteger(current.GetValue(Grid.RowProperty));
if (rowIndex < 1) continue;
if (rowIndex > num)
{
current.SetValue(Grid.RowProperty, rowIndex - 2 < 0 ? 0 : rowIndex - 2);
}
else if (rowIndex == num - 1 && current is GridSplitter)
{
currentSplitter = current;
}
}
}
if (currentSplitter != null)
{
_chartPanesGrid.Children.Remove(currentSplitter);
_chartPanesGrid.RowDefinitions.RemoveAt(num - 1);
}
aPane.RemoveAllScaleLayers();
Refresh(true);
}
internal void SetCursorImagePos(bool showIt, MouseEventArgs e)
{
if (showIt)
{
switch (PointerType)
{
case PointerType.CursorWithData:
_crossHairGrid.Cursor = Cursors.Arrow;
_chartPanesGrid.Cursor = Cursors.Arrow;
_toolImage.Source = null;
break;
case PointerType.Cursor:
_crossHairGrid.Cursor = Cursors.Arrow;
_chartPanesGrid.Cursor = Cursors.Arrow;
_toolImage.Source = null;
break;
case PointerType.Pan:
_crossHairGrid.Cursor = Cursors.Hand;
_chartPanesGrid.Cursor = Cursors.Hand;
_toolImage.Source = null;
break;
case PointerType.Erase:
_crossHairGrid.Cursor = Cursors.Arrow;
_toolImage.Source = ImageHelper.GetImage("Eraser.png");
break;
case PointerType.Drawing:
_toolImage.Source = CurrentDrawingTool == null ? null : CurrentDrawingTool.Icon();
break;
}
if (_toolImage.Source == null)
{
CleanQuoteBoard();
}
else
{
if (_popup == null)
{
_popup = new Popup
{
Child = _toolImage,
Placement = PlacementMode.Relative,
AllowsTransparency = true
};
_chartPanesGrid.Children.Add(_popup);
_popup.IsOpen = true;
}
}
}
else
{
CleanQuoteBoard();
}
//}
if (showIt && e != null && _toolImage.Source != null)
{
Point position = e.GetPosition(_chartPanesGrid);
_popup.HorizontalOffset = (position.X + 8.0);
_popup.VerticalOffset = (position.Y - 8.0);
}
else
{
if (!showIt)
{
CleanQuoteBoard();
}
}
}
///
/// 设置当前画图工具为null
///
internal void SetDrawingTool()
{
_oldDrawingTool = CurrentDrawingTool;
CurrentDrawingTool = null;
_pointerType = _oldPointerType;
DrawingToolExecute();
var panes = AllPanes();
foreach (var current in panes)
{
current.OnDrawing();
}
_drawingToolbar.ButtonPress();
}
///
/// 显示/隐藏Download More Button
///
/// if set to true [is show].
internal void ShowDownloadButton(bool isShow)
{
if (isShow)
{
_downloadMoreButton.Width = DateChartSlider.Height;
_downloadMoreButton.Height = DateChartSlider.Height;
_downloadMoreButton.Visibility = Visibility.Visible;
}
else
{
_downloadMoreButton.Visibility = Visibility.Collapsed;
}
}
#endregion Internal Methods
#region Protected Methods
///
/// 鼠标滚轮事件
///
/// 包含事件数据的 。
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
e.Handled = true;
var factor = 1;
if ((Keyboard.Modifiers & AcceleratedWheelModifierKeys) == AcceleratedWheelModifierKeys)
{
factor = AcceleratedWheelFactor;
}
int num = DateScaler.NumBars + (factor) * (int)Math.Round((double)e.Delta / 120.0);
num = num < 5 ? 5 : num;
var scalerCount = DateScaler.Count();
num = num > scalerCount ? scalerCount : num;
DateScaler.NumBars = num;
Refresh();
}
#endregion Protected Methods
#region Private Static Methods
private static void ChartFontSizeProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = d as Chart;
if (chart == null) return;
UpdateDrawingTool(chart);
}
private static void ChartLanguageProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ChartLanguageType language;
if (!Enum.TryParse(e.NewValue.ToString(), out language))
{
language = ChartLanguageType.SimplifiedChinese;
}
switch (language)
{
case ChartLanguageType.SimplifiedChinese:
LanguageManager.SetLanguage("zh-CN");
break;
case ChartLanguageType.TraditionalChinese:
LanguageManager.SetLanguage("zh-TW");
break;
case ChartLanguageType.English:
LanguageManager.SetLanguage("en-US");
break;
default:
LanguageManager.SetLanguage("zh-CN");
break;
}
var chart = d as Chart;
if (chart == null) return;
UpdateDrawingTool(chart);
}
private static void ChartLineTypePlotProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
//更新plot type
var newValue = (LinePlotType)e.NewValue;
var pricePlot = chart.GetPlot("main");
if (pricePlot != null && pricePlot.Indicator != null) pricePlot.Indicator.LinePlotType = newValue;
var comparisonPlot = chart.GetPlot("main");
if (comparisonPlot != null && comparisonPlot.Indicator != null) comparisonPlot.Indicator.LinePlotType = newValue;
chart.Refresh();
}
private static void ChartCycleBarVisibity(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart.TimeSpanPicker != null)
{
chart.TimeSpanPicker.Visibility = (Visibility)e.NewValue;
}
}
///
/// 图的最小最大记录改变.
///
/// The d.
/// The instance containing the event data.
private static void ChartMinMaxRecordProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
var numBars = chart.DateScaler.NumBars;
var oldNum = (int)e.OldValue;
var newNum = (int)e.NewValue;
//numBars为矩形柱间距,矩形柱数量实际要-1
if (numBars == 4 || numBars == oldNum - 1)
{
chart.DateScaler.NumBars = newNum - 1;
chart.Refresh();
}
}
///
/// Charts the property_ changed.
///
/// The d.
/// The instance containing the event data.
private static void ChartProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart == null) return;
if ((e.Property == FillComparisonCandleProperty && chart.LinePlotType == LinePlotType.Candlestick &&
chart.ComparisionDictionary.Any())
|| e.Property != FillComparisonCandleProperty)
{
chart.Refresh();
}
}
///
/// Charts the record count property_ changed.
///
/// The d.
/// The instance containing the event data.
private static void ChartRecordCountProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
//numBars为矩形柱间距,矩形柱数量实际要-1
chart.DateScaler.NumBars = (int)e.NewValue - 1;
chart.Refresh();
}
///
/// Charts the time span property_ changed.
///
/// The d.
/// The instance containing the event data.
private static void ChartTimeSpanProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart == null) return;
if (chart.ChartTimeSpan != default(TimeSpan))
{
if (chart.CycleType == CycleType.Custom)
{
//直接调用
chart.CycleTypePropertyChanged(false);
}
else
{
//通过设置CycleType触发数据下载
chart.CycleType = CycleType.Custom;
}
}
}
///
/// Currents the goods property_ changed.
///
/// The d.
/// The instance containing the event data.
private static void CurrentGoodsProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart == null) return;
// chart.ClearComparison();
chart.OnCycleTypeChanged(true);
}
///
/// 周期属性改变后回调函数
///
/// The Dependency Object.
/// The instance containing the event data.
private static void ChartCycleTypeProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart == null) return;
chart.CycleTypePropertyChanged(CycleType.TimeSharing.Equals(e.OldValue) || CycleType.Tik.Equals(e.OldValue));
}
///
/// 周期集合属性改变后回调函数
///
/// The Dependency Object.
/// The instance containing the event data.
private static void ChartCycleTypeItemsProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart == null || chart.TimeSpanPicker == null) return;
}
///
/// Tik属性改变后回调函数
///
private static void ChartTikProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart == null) return;
if (chart.CurrentTik != null && chart.DataSet != null && chart.DataSet.DataPoints != null && chart.DataSet.DataPoints.Count() > 0)
{
var lastTik = chart.DataSet.DataPoints.Last() as BarDataPoint;
var date = default(DateTime);
if (chart.IsNotInCycle(chart.CurrentTik.Date, ref date))
{
var item = new BarDataPoint(date, chart.CurrentTik.Open, chart.CurrentTik.High, chart.CurrentTik.Low, chart.CurrentTik.Close, chart.CurrentTik.Volume,
chart.CurrentTik.Turnover, chart.CurrentTik.HoldVolume);
chart.DataSet.DataPoints.Add(item);
chart.SetDatesAndRefresh(true,false);
}
else
{
var barPointTmp = chart.DataSet.DataPoints.Last() as BarDataPoint;
barPointTmp.Close = chart.CurrentTik.Close;
barPointTmp.High = chart.CurrentTik.Value > lastTik.High ? chart.CurrentTik.Value : lastTik.High;
barPointTmp.Low = chart.CurrentTik.Value < lastTik.Low ? chart.CurrentTik.Value : lastTik.Low;
barPointTmp.HoldVolume = chart.CurrentTik.HoldVolume;
barPointTmp.Turnover = chart.CurrentTik.Turnover;
barPointTmp.Volume += chart.CurrentTik.Volume;
chart.SetDatesAndRefresh(true, false);
}
}
}
///
/// Drawings the tool position property_ changed.
///
/// The d.
/// The instance containing the event data.
private static void DrawingToolPositionProperty_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
chart.InitializeDrawingTool();
}
///
/// Currents the drawing tool type_ changed.
///
/// The d.
/// The instance containing the event data.
private static void DrawingToolType_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var chart = (Chart)d;
if (chart == null || chart._drawingToolbar == null) return;
var button = chart._drawingToolbar.GetToolbarButton(chart.DrawingToolType);
if (button == null) return;
button.ButtonClick();
}
///
/// Updates the drawing tool.
///
/// The chart.
private static void UpdateDrawingTool(Chart chart)
{
if (chart == null) return;
//更新画图工具
if (chart._drawingToolStackPanel != null)
{
chart._drawingToolStackPanel.Children.Clear();
chart._drawingToolbar = new ChartDrawingToolbar(chart);
chart._chartToolbarExpander = new ChartToolbarExpander(chart._drawingToolbar);
chart.InitializeDrawingTool();
}
//更新图表
chart.Refresh();
}
#endregion Private Static Methods
#region Private Methods
///
/// 刷新叠加商品
///
private void RefreshComparsionGoods()
{
if (_comparisonGoodsList != null && _comparisonGoodsList.Any())
{
var list = new List();
list.AddRange(_comparisonGoodsList);
SetComparisonGoodsList(list);
}
}
///
/// 获取主图所在的图表容器
///
///
private ChartPane GetMainChartPane()
{
foreach (var chartPane in _chartPanes)
{
if (IsMainChartPane(chartPane)) return chartPane;
}
return null;
}
///
/// 判断是否是主图容器
///
///
///
private bool IsMainChartPane(ChartPane chartPane)
{
foreach (var scaleLayer in chartPane.AllScaleLayers)
{
foreach (var displayFormula in scaleLayer.AllDisplayFormula)
{
if (displayFormula.FormulaModel != null && displayFormula.FormulaModel.IsMain)
{
return true;
}
}
}
return false;
}
///
/// 添加pane(图例)
///
///
///
///
private ChartPane AddChartPane(ChartPane p, double stars, bool isMain = false)
{
int count = _chartPanesGrid.RowDefinitions.Count;
if (count > 0)
{
AddRowDefinition(count, 1, GridUnitType.Auto);
var splitter = new GridSplitter();
splitter.IsTabStop = (false);
splitter.Background = (new SolidColorBrush(ColorHelper.DimGray));
splitter.SetValue(Grid.RowProperty, count);
splitter.SetValue(Grid.ColumnProperty, 1);
splitter.SetValue(Grid.ColumnSpanProperty, 2);
splitter.HorizontalAlignment = HorizontalAlignment.Stretch;
splitter.VerticalAlignment = VerticalAlignment.Center;
splitter.Height = (2.0);
splitter.Cursor = Cursors.SizeNS;
splitter.Margin = new Thickness(0, 2, 0, 2);
_chartPanesGrid.Children.Add(splitter);
//AddRowDefinition(count + 1, stars <= 0.0 ? 1.0 : stars, GridUnitType.Star);
AddRowDefinition(count + 1, isMain ? 2 : 1, GridUnitType.Star);
}
else
{
AddRowDefinition(count, isMain ? 2 : 1, GridUnitType.Star);
//AddRowDefinition(count, stars <= 0.0 ? 1.0 : stars, GridUnitType.Star);
}
p.SetValue(Grid.RowProperty, count > 0 ? count + 1 : 0);
p.SetValue(Grid.ColumnProperty, 1);
_chartPanesGrid.Children.Add(p);
_chartPanes.Add(p);
if (p.RightScaleControl != null)
{
p.RightScaleControl.SetValue(Grid.RowProperty, count > 0 ? count + 1 : 0);
p.RightScaleControl.SetValue(Grid.ColumnProperty, 2);
_chartPanesGrid.Children.Add(p.RightScaleControl);
}
if (p.LeftScaleControl != null)
{
p.LeftScaleControl.SetValue(Grid.RowProperty, count > 0 ? count + 1 : 0);
p.LeftScaleControl.SetValue(Grid.ColumnProperty, 0);
_chartPanesGrid.Children.Add(p.LeftScaleControl);
}
return p;
}
///
/// 添加默认指标器-历史价格,成交量
///
private void AddDefaultIndicators()
{
AddFormula(new DisplayFormula(new FormulaModel("Main"), DataSet, this), true);
var indecators = _defaoltIndecator.Split(',');
foreach (var indecator in indecators)
{
AddIndicatorByName(indecator, false);
}
var menuItem = FormulaHelper.CreateIndicatorMenu("", IndicatorItemClick);
menuItem.Header = "指标";
this.ContextMenu = new ContextMenu();
this.ContextMenu.Items.Add(menuItem);
var menuItem1 = new MenuItem() { Header = "编辑参数" };
this.ContextMenu.Items.Add(menuItem1);
menuItem1.Click += menuItem1_Click;
var MainItem = new MenuItem() { Header = "清除主图" };
this.ContextMenu.Items.Add(MainItem);
MainItem.Click += MainItem_Click;
//打开公式管理器
MainItem = new MenuItem() { Header = "公式管理" };
this.ContextMenu.Items.Add(MainItem);
MainItem.Click += (cs, ce) =>
{
OpenFormulEditer();
};
}
//清楚主图中的指标
void MainItem_Click(object sender, RoutedEventArgs e)
{
ClearMainPaneIndicator();
}
///
/// 设置当前公式的参数
///
///
///
void menuItem1_Click(object sender, RoutedEventArgs e)
{
SetCurrectFormulaParam();
}
//选择指标菜单时触发的事件处理
private void IndicatorItemClick(object sender, RoutedEventArgs e)
{
var selectItem = sender as MenuItem;
if (selectItem != null && selectItem.Tag is ProgramModel)
{
var formulaModel = (selectItem.Tag as ProgramModel);
AddIndicatorByName(formulaModel.Name);
}
}
private void AddFormula(DisplayFormula displayFormula, bool allowDefaults)
{
AddFormula(displayFormula, allowDefaults, null, true);
}
public ChartPane AddFormula(DisplayFormula displayFormula, bool allowDefaults, ChartPane addToPane, bool isMain = false)
{
ChartPane pane = addToPane;
bool flag = addToPane == null;
if (flag)
{
pane = new ChartPane(this);
//取最大grid高度做*
var stars = _chartPanesGrid.RowDefinitions.Count > 0
? _chartPanesGrid.RowDefinitions.Max(z => z.Height.Value)
: 1.0;
AddChartPane(pane, stars, isMain);
}
ScaleLayer scaleLayer = null;
if (flag)
{
scaleLayer = new ScaleLayer();
pane.AddScaleLayer(scaleLayer);
}
else
{
if (IsMainChartPane(pane))
{
scaleLayer = GetMainScaleLayer();
}
else
{
scaleLayer = new ScaleLayer();
pane.AddScaleLayer(scaleLayer);
}
}
displayFormula.PlotBases.Clear();
scaleLayer.AllDisplayFormula.Add(displayFormula);
displayFormula.ScaleLayer = scaleLayer;
pane.DisplayFristGrid();
return pane;
}
///
/// 添加指标时如主图指标则添加到主图,副图指标添加或替换.副图不能添加超过允许最大数量
///
/// 指标公式
///
///
///
public ChartPane AddFormulaFromPane(DisplayFormula displayFormula)
{
ChartPane pane = null;
var flag = displayFormula.FormulaModel.IsMainIndicator;
//var scaleLayer = new ScaleLayer();
ScaleLayer scaleLayer = new ScaleLayer();
if (flag)
{
pane = GetMainChartPane();
scaleLayer = GetMainScaleLayer();
}
else
{
var maxChart = MaxChartPaneCount > 0 && _chartPanes.Count >= MaxChartPaneCount;
if (!maxChart) //超过最大数量限制
{
pane = new ChartPane(this);
//取最大grid高度做*
var stars = _chartPanesGrid.RowDefinitions.Count > 0
? _chartPanesGrid.RowDefinitions.Max(z => z.Height.Value)
: 1.0;
AddChartPane(pane, stars);
}
else
{
pane = _chartPanes[_chartPanes.Count - 1];
pane.RemoveAllScaleLayers();
}
scaleLayer = new ScaleLayer();
pane.AddScaleLayer(scaleLayer);
}
displayFormula.PlotBases.Clear();
scaleLayer.AllDisplayFormula.Add(displayFormula);
displayFormula.ScaleLayer = scaleLayer;
pane.DisplayFristGrid();
return pane;
}
///
/// 在ChartCont指点位置插入一行
///
///
///
///
private void AddRowDefinition(int index, double value, GridUnitType type)
{
var rowDefinition = new RowDefinition { Height = new GridLength(value, type) };
_chartPanesGrid.RowDefinitions.Insert(index, rowDefinition);
}
///
/// 添加图表底部控件
///
private void BuildBottomControls()
{
var grid = new Grid();
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) });
grid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) });
//隐藏用hidden,不用Collapsed,需要用来占位
_downloadMoreButtonPlaceHolder = new TextBlock() { Visibility = Visibility.Hidden };
_downloadMoreButton = new Button()
{
Visibility = Visibility.Collapsed
};
_downloadMoreButton.Click -= DownloadMoreButton_Click;
_downloadMoreButton.Click += DownloadMoreButton_Click;
_downloadMoreButton.MouseEnter -= DownloadMoreButton_MouseEnter;
_downloadMoreButton.MouseEnter += DownloadMoreButton_MouseEnter;
_downloadMoreButton.SetValue(Grid.ColumnProperty, 0);
_downloadMoreButtonPlaceHolder.SetValue(Grid.ColumnProperty, 0);
var style = (Style)FindResource("LeftArrowButton");
_downloadMoreButton.Style = style;
var gridRight = new Grid();
gridRight.Children.Add(DateChartSlider);
gridRight.Children.Add(TimeSpanPicker); //不再大小图表上显示周期
gridRight.SetValue(Grid.ColumnProperty, 1);
grid.Children.Add(gridRight);
var gridLeft = new Grid { HorizontalAlignment = HorizontalAlignment.Right };
gridLeft.Children.Add(_downloadMoreButton);
gridLeft.Children.Add(_downloadMoreButtonPlaceHolder);
gridLeft.SetValue(Grid.ColumnProperty, 0);
grid.Children.Add(gridLeft);
_dateChartSliderStackPanel.Children.Add(_dateScaleDisplay);
_dateChartSliderStackPanel.Children.Add(grid);
}
///
/// 生成控件
///
private void BuildParts()
{
_exportBusyIndicator = (BusyIndicator)TreeHelper.TemplateFindName("PART_BusyIndicator", this);
_exportBusyIndicator.IsBusy = false;
_exportBusyIndicator.BusyContent = LanguageManager.FindResource(LanguageConst.ExportWaiting);
_mainGrid = (Grid)TreeHelper.TemplateFindName("PART_MainGrid", this);
_mainGrid.MouseEnter -= MainGrid_MouseEnter;
_mainGrid.MouseEnter += MainGrid_MouseEnter;
_mainGrid.MouseMove -= MainGrid_MouseMove;
_mainGrid.MouseMove += MainGrid_MouseMove;
_mainGrid.MouseDown -= _mainGrid_MouseDown;
_mainGrid.MouseDown += _mainGrid_MouseDown;
_mainGrid.PreviewKeyDown += _mainGrid_PreviewKeyDown;
_chartHeaderStackPanel = (StackPanel)TreeHelper.TemplateFindName("PART_HeaderStackPanel", this);
_drawingToolStackPanel = (StackPanel)TreeHelper.TemplateFindName("PART_DrawingToolStackPanel", this);
_chartPanesGrid = (Grid)TreeHelper.TemplateFindName("PART_ChartPanesGrid", this);
_dateChartSliderStackPanel =
(StackPanel)TreeHelper.TemplateFindName("PART_DateChartSliderStackPanel", this);
_crossHairGrid = (Canvas)TreeHelper.TemplateFindName("PART_CrossHairGrid", this);
_crossHairGrid.LostMouseCapture -= CrossHairGrid_LostMouseCapture;
_crossHairGrid.LostMouseCapture += CrossHairGrid_LostMouseCapture;
_crossHairGrid.MouseEnter -= CrossHairGrid_MouseEnter;
_crossHairGrid.MouseEnter += CrossHairGrid_MouseEnter;
_crossHairGrid.MouseLeave -= CrossHairGrid_MouseLeave;
_crossHairGrid.MouseLeave += CrossHairGrid_MouseLeave;
_crossHairGrid.MouseLeftButtonDown -= CrossHairGrid_MouseLeftButtonDown;
_crossHairGrid.MouseLeftButtonDown += CrossHairGrid_MouseLeftButtonDown;
_crossHairGrid.MouseLeftButtonUp -= CrossHairGrid_MouseLeftButtonUp;
_crossHairGrid.MouseLeftButtonUp += CrossHairGrid_MouseLeftButtonUp;
_crossHairGrid.MouseMove -= CrossHairGrid_MouseMove;
_crossHairGrid.MouseMove += CrossHairGrid_MouseMove;
_pointerPopup = (Popup)TreeHelper.TemplateFindName("PART_PointerPopup", this);
_pointerGrid = (Grid)TreeHelper.TemplateFindName("PART_PointerGrid", this);
}
void _mainGrid_PreviewKeyDown(object sender, KeyEventArgs e)
{
//鼠标上键
if (Keyboard.IsKeyDown(Key.Down))
{
this._crossHairGrid_IsDoubleClick = false;
this.HiddenCrossHairGrid();
if (this.RecordCount + this.LeftRightKeyToAcceleration < this.MaxRecordCount)
{
this.RecordCount += this.LeftRightKeyToAcceleration;
}
else
{
this.RecordCount = this.MaxRecordCount;
}
}
else if (Keyboard.IsKeyDown(Key.Up)) //鼠标下键
{
this._crossHairGrid_IsDoubleClick = false;
this.HiddenCrossHairGrid();
if (this.RecordCount - this.LeftRightKeyToAcceleration > this.MinRecordCount)
{
this.RecordCount -= this.LeftRightKeyToAcceleration;
}
else
{
this.RecordCount = this.MinRecordCount;
}
}
else if (Keyboard.IsKeyDown(Key.Left)) //鼠标左键
{
Mouse.OverrideCursor = Cursors.None;
this.DrawingCross(false);
}
else if (Keyboard.IsKeyDown(Key.Right)) //鼠标右键
{
Mouse.OverrideCursor = Cursors.None;
this.DrawingCross(true);
}
else if (Keyboard.IsKeyDown(Key.Escape))
{
this._crossHairGrid_IsDoubleClick = false;
this.HiddenCrossHairGrid();
Mouse.OverrideCursor = Cursors.Arrow;
}
e.Handled = true;
}
private void _mainGrid_MouseDown(object sender, MouseButtonEventArgs e)
{
_mainGrid.Focusable = true;
FocusManager.SetFocusedElement(_mainGrid, _mainGrid);
}
///
/// 获取和设置the root panel
/// 代替PopupManager.PopupRoot,一个应用程序多图表时,popup只针对当前图表
///
internal Panel RootPanel
{
get
{
return _mainGrid;
}
}
///
/// 计算历史周期涨幅
///
/// IList{ILineDataPoint}.
private List CaclulateCycleDataIncrease(List source)
{
return source;
}
///
/// 计算分时数据涨幅
///
/// The source.
private void CaclulateTikDataIncrease(IList source)
{
if (source == null || !source.Any()) return;
foreach (var lineDataPoint in source)
{
var current = lineDataPoint as IOHLCDataPoint;
if (current == null) continue;
current.Increase = CurrentGoods.PreClose.Equals(0)
? 0f
: (current.Close - CurrentGoods.PreClose) / CurrentGoods.PreClose;
current.IncreaseValue = CurrentGoods.PreClose.Equals(0) ? 0f : (current.Close - CurrentGoods.PreClose);
}
}
///
/// 清除报价牌
///
private void CleanQuoteBoard()
{
bool flag = _popup != null;
if (flag)
{
_popup.Child = (null);
_chartPanesGrid.Children.Remove(_popup);
_popup = null;
}
}
private void CrossHairGrid_LostMouseCapture(object sender, MouseEventArgs e)
{
if (CurrentGoods == null || string.IsNullOrWhiteSpace(CurrentGoods.Symbol)) return;
if (_crossFlag)
{
if (PointerType != PointerType.Pan)
{
_crossHairGrid.Children.Clear();
var panes = AllPanes();
foreach (var chartPane in panes)
{
var layers = chartPane.AllScaleLayers;
if (layers == null || !layers.Any()) continue;
foreach (var scaleLayer in layers)
{
var left = scaleLayer.GetLeftValueScaleDisplay();
var right = scaleLayer.GetRightValueScaleDisplay();
if (left != null) left.BuildYList();
if (right != null) right.BuildYList();
}
}
}
_crossFlag = false;
_pointerPopup.IsOpen = false;
if (_mainGrid.Children.Contains(_pointerPopup))
{
_mainGrid.Children.Remove(_pointerPopup);
}
}
}
private void CrossHairGrid_MouseEnter(object sender, MouseEventArgs e)
{
if (CurrentGoods == null || string.IsNullOrWhiteSpace(CurrentGoods.Symbol)) return;
SetCursorImagePos(true, e);
DrawingToolExecute();
}
private void CrossHairGrid_MouseLeave(object sender, MouseEventArgs e)
{
if (CurrentGoods == null || string.IsNullOrWhiteSpace(CurrentGoods.Symbol)) return;
SetCursorImagePos(false, e);
}
private int _crossHairGrid_ClickTik = 0;
public bool _crossHairGrid_IsDoubleClick = false;
private void CrossHairGrid_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
_crossHairGrid_ClickTik += 1;
DispatcherTimer timer = new DispatcherTimer();
timer.Interval = new TimeSpan(0, 0, 0, 0, 300);
timer.Tick += (cs, ce) =>
{
timer.IsEnabled = false;
_crossHairGrid_ClickTik = 0;
};
timer.IsEnabled = true;
if (_crossHairGrid_ClickTik % 2 == 0)
{
timer.IsEnabled = false;
_crossHairGrid_ClickTik = 0;
_crossHairGrid_IsDoubleClick = !_crossHairGrid_IsDoubleClick;
if (CurrentGoods == null || string.IsNullOrWhiteSpace(CurrentGoods.Symbol))
{
return;
}
else
{
if (Keyboard.Modifiers == (ModifierKeys)2 && _oldDrawingTool != null)
{
SetDrawingTool(_oldDrawingTool);
var panes = AllPanes();
foreach (var current in panes)
{
Point position = e.GetPosition(current.PaintArea);
if (position.X >= 0.0 && position.Y >= 0.0 && position.X <= current.PaintArea.ActualWidth &&
position.Y <= current.PaintArea.ActualHeight)
{
current.SimulateDrawingMouseDown(RuntimeHelpers.GetObjectValue(sender), e);
break;
}
}
}
else
{
_crossHairGrid.CaptureMouse();
_crossFlag = true;
if (PointerType == PointerType.Pan)
{
_crossX = (float)e.GetPosition(_crossHairGrid).X;
_crossDateTime = DateScaler.DateFromX(_crossX);
}
else
{
if (PointerType == PointerType.CursorWithData)
{
_pointerPopup.IsOpen = true;
}
if (_crossHairGrid.Children.Count == 0)
{
_crossHairGrid.Children.Add(_hline);
_crossHairGrid.Children.Add(_vline);
}
DrawingCross(e);
}
}
}
}
}
private void CrossHairGrid_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
if (CurrentGoods == null || string.IsNullOrWhiteSpace(CurrentGoods.Symbol)) return;
if (_crossFlag)
{
if (!_crossHairGrid_IsDoubleClick)
{
_crossHairGrid.ReleaseMouseCapture();
if (PointerType == PointerType.Pan)
{
MoveChartPane(e);
}
else
{
_crossHairGrid.Children.Clear();
var panes = AllPanes();
var scaleLayerList = panes.Select(chartPane => chartPane.AllScaleLayers)
.Where(layers => layers != null && layers.Any())
.SelectMany(layers => layers)
.ToList();
foreach (var scaleLayer in scaleLayerList)
{
scaleLayer.GetRightValueScaleDisplay().BuildYList();
scaleLayer.GetLeftValueScaleDisplay().BuildYList();
}
}
_crossFlag = false;
_pointerPopup.IsOpen = false;
}
}
}
public void HiddenCrossHairGrid()
{
_crossHairGrid.ReleaseMouseCapture();
_pointerPopup.IsOpen = false;
}
DateTime LastRedrawTime = DateTime.Now;
private Point lastPoint = new Point();
private void CrossHairGrid_MouseMove(object sender, MouseEventArgs e)
{
Mouse.OverrideCursor = Cursors.Arrow;
if (CurrentGoods == null || string.IsNullOrWhiteSpace(CurrentGoods.Symbol))
{
return;
}
if (_crossHairGrid_IsDoubleClick)
{
this.Cursor = Cursors.None;
}
else
{
this.Cursor = Cursors.Arrow;
}
SetCursorImagePos(true, e);
if (_crossFlag)
{
if (PointerType == PointerType.Pan)
{
MoveChartPane(e);
}
else
{
DrawingCross(e);
}
}
}
///
/// Handles the Click event of the _downloadMoreButton control.
///
/// The source of the event.
/// The instance containing the event data.
private void DownloadMoreButton_Click(object sender, RoutedEventArgs e)
{
_downloadMoreButton.Visibility = Visibility.Collapsed;
DownloadNextDataBlock();
}
private void DownloadMoreButton_MouseEnter(object sender, MouseEventArgs e)
{
_downloadMoreButton.ToolTip =
string.Format(LanguageManager.FindResource(LanguageConst.ToolTip_DownloadMore), MaxLoadRecordCount);
}
///
/// 更新图表
///
private void DrawingChart(bool isUpdataSet)
{
if (_chartPanesGrid == null) return;
if (CycleType == CycleType.TimeSharing)
{
DrawingTimeShareChart();
return; //分时图不使用这个方法更新图表
}
var allDateScaler = (AllDateScaler)DateScaler;
var width = (int)GetChartPaneWidth();
width = Math.Max(0, width);
var left = (float)GetChartPanelOffset();
allDateScaler.SetPlotInfo(width, left);
_dateScaleDisplay.BuildCanvas(allDateScaler, left, width, false);
//DateChartSlider.Margin = new Thickness(left, 0, 0, 0);
_downloadMoreButtonPlaceHolder.Width = left;
DateChartSlider.BuildDateChartSlider();
ShowDownloadButton(allDateScaler.StartDateIndex == 0);
var chartPanes = _chartPanesGrid.Children.OfType();
var childrenCount = chartPanes.Count();
var paneIndex = 0;
if (CycleType == CycleType.Tik)
{
foreach (var current in _chartPanesGrid.Children)
{
var pane = current as ChartPane;
if (pane != null)
{
//最后一个ChartPane时更新
pane.RefreshChartFlag = true;
pane.BuildTimeShareChartPane(allDateScaler, _dateScaleDisplay);
}
}
}
else
{
foreach (var current in chartPanes)
{
paneIndex++;
if (current != null)
{
//最后一个ChartPane时更新
current.RefreshChartFlag = paneIndex == childrenCount;
current.BuildChartPane(allDateScaler, _dateScaleDisplay, isUpdataSet);
}
}
}
}
///
/// 创建分时图
///
private void DrawingTimeShareChart()
{
if (_chartPanesGrid == null) return;
var width = (int)GetChartPaneWidth();
width = Math.Max(0, width);
var left = (float)GetChartPanelOffset();
var allDateScaler = CreateDateScaler(width, left);
DateScaler = allDateScaler;
_dateScaleDisplay.BuildTimeShareCanvas(allDateScaler, left, width, false,
CurrentGoods.OpenCloseTimes, this);
int paneIndex = 0;
foreach (var current in _chartPanesGrid.Children)
{
var pane = current as ChartPane;
if (pane != null)
{
//最后一个ChartPane时更新
pane.RefreshChartFlag = paneIndex == 1;
pane.BuildTimeShareChartPane(allDateScaler, _dateScaleDisplay);
paneIndex++;
}
}
}
///
/// 创建分时图的时间轴
///
private AllDateScaler CreateDateScaler(int width, float left)
{
int count = SetCountPoint();
var dateScaler = new AllDateScaler(this)
{
NumBars = count,
DesiredEndDate = DateTime.Today.AddMinutes(count),
};
dateScaler.SetPlotInfo(width, left);
var dataPoints = new List();
if (CurrentGoods == null || CurrentGoods.OpenCloseTimes == null) return dateScaler;
var timeSpan = TimeSpan.Zero;
foreach (var openCloseTimes in CurrentGoods.OpenCloseTimes)
{
timeSpan = openCloseTimes.CloseTime - openCloseTimes.OpenTime;
for (int i = 0; i <= timeSpan.TotalMinutes; i++)
{
dataPoints.Add(new BarDataPoint(openCloseTimes.OpenTime.AddMinutes(i), 0));
}
}
dateScaler.SetDates(dataPoints, CurrentTimeFrame, false);
return dateScaler;
}
///
/// 十字光标按下时画交叉线
///
/// The instance containing the event data.
private void DrawingCross(MouseEventArgs e)
{
var position = e.GetPosition(_crossHairGrid);
_currentX = position.X;
_currentY = position.Y;
currentX = _currentX;
currentY = _currentY;
_offSetNum = 0;
//限制超出ChartPane时十字光标的显示-新增OriginalDateValue, OriginalDateFromX
var start = DateScaler.OriginalDateValue(DateScaler.StartDateIndex);
var end = DateScaler.OriginalDateValue(DateScaler.EndDateIndex);
var distance = DateScaler.DistanceBetweenDates();
_currentX -= (float)distance / 2;
var aDate = (_currentX <= 0 || _currentX < distance) ? start : DateScaler.OriginalDateFromX(_currentX - 5);
if (aDate.Equals(DateTime.MinValue) || aDate > end)
{
aDate = end;
}
if (aDate.Equals(DateTime.MinValue) || aDate < start)
{
aDate = start;
}
//显示报价牌
ShowQuoteBoard(aDate);
var num = (float)((int)Math.Round((double)DateScaler.XforDate(aDate)));
//5.0f 是PART_ChartPanesGrid的Margin, 0.5f在LinePlot/DateScaleDisplay里都加有0.5的微调
//另外加上左边纵坐标引起的位移
num = num + 5f + 0.5f + (float)GetChartPanelOffset();
var y = _currentY < 0 ? 0 : _currentY;
var with = _crossHairGrid.ActualWidth;
var height = _crossHairGrid.ActualHeight;
var brush = IsDarkBackground
? (new SolidColorBrush(Colors.White))
: (new SolidColorBrush(Colors.Black));
_hline.X1 = 0;
_hline.X2 = with;
_hline.Y1 = y;
_hline.Y2 = y;
_hline.Stroke = brush;
_vline.X1 = num;
_vline.X2 = num;
_vline.Y1 = 0;
_vline.Y2 = height;
_vline.Stroke = brush;
var panes = AllPanes();
foreach (var current in panes)
{
var position2 = e.GetPosition(current);
bool flag = position2.Y >= 0.0 && position2.Y <= current.ActualHeight;
var layers = current.AllScaleLayers;
if (layers == null || !layers.Any()) continue;
foreach (var scaleLayer in layers)
{
var left = scaleLayer.GetLeftValueScaleDisplay();
var right = scaleLayer.GetRightValueScaleDisplay();
if (flag)
{
if (left != null) left.BuildYList((float)position2.Y);
if (right != null) right.BuildYList((float)position2.Y);
}
else
{
if (left != null) left.BuildYList();
if (right != null) right.BuildYList();
}
}
}
}
///
/// 十字光标按下时画交叉线
///
/// The instance containing the event data.
public void DrawingCross(bool isAddTime = true)
{
_offSetNum += isAddTime ? 1 : -1;
var aDate = DateScaler.OriginalDateFromX(currentX - 5, _offSetNum);
if (DateScaler.XforDate(aDate) < 0)
{
_offSetNum += (!isAddTime) ? 1 : -1;
return;
}
if (DateScaler.XforDate(aDate) > _chartPanesGrid.ActualWidth)
{
_offSetNum += (!isAddTime) ? 1 : -1;
return;
}
//显示报价牌
ShowQuoteBoard(aDate);
var num = (float)((int)Math.Round((double)DateScaler.XforDate(aDate)));
//5.0f 是PART_ChartPanesGrid的Margin, 0.5f在LinePlot/DateScaleDisplay里都加有0.5的微调
//另外加上左边纵坐标引起的位移
num = num + 5f + 0.5f + (float)GetChartPanelOffset();
var y = _currentY < 0 ? 0 : _currentY;
var with = _crossHairGrid.ActualWidth;
var height = _crossHairGrid.ActualHeight;
var brush = IsDarkBackground ? (new SolidColorBrush(Colors.White)) : (new SolidColorBrush(Colors.Black));
_hline.X1 = 0;
_hline.X2 = with;
_hline.Y1 = y;
_hline.Y2 = y;
_hline.Stroke = brush;
_vline.X1 = num;
_vline.X2 = num;
_vline.Y1 = 0;
_vline.Y2 = height;
_vline.Stroke = brush;
var panes = AllPanes();
foreach (var current in panes)
{
bool flag = currentY >= 0.0 && currentY <= current.ActualHeight;
var layers = current.AllScaleLayers;
if (layers == null || !layers.Any()) continue;
foreach (var scaleLayer in layers)
{
var left = scaleLayer.GetLeftValueScaleDisplay();
var right = scaleLayer.GetRightValueScaleDisplay();
if (flag)
{
if (left != null) left.BuildYList((float)currentY);
if (right != null) right.BuildYList((float)currentY);
}
else
{
if (left != null) left.BuildYList();
if (right != null) right.BuildYList();
}
}
}
}
///
/// 加载叠加商品数据
///
/// The comparison goods.
/// IList{ILineDataPoint}.
private List LoadComparisonDataSet(ComparisonGoods comparisonGoods)
{
//历史数据回补后叠加商品记录条数以当前主商品记录条数为准
var flag = DataSet == null || DataSet.DataPoints == null || !DataSet.DataPoints.Any();
if (flag) return null;
var count = DataSet.DataPoints.Count;
var endTime = DataSet.DataPoints.Max(z => z.Date);
return OnLoadHistoryCycleData(comparisonGoods, CycleType, CurrentTimeFrame, MaxLoadRecordCount, endTime);
}
///
/// Loads the configs from XML.
///
/// Name of the config.
private void LoadConfigsFromXml(string configName)
{
//to-do:
}
///
/// Handles the MouseEnter event of the MainGrid control.
///
/// The source of the event.
/// The instance containing the event data.
private void MainGrid_MouseEnter(object sender, MouseEventArgs e)
{
if (CurrentDrawingTool != null)
{
SetDrawingTool(CurrentDrawingTool);
}
else
{
DrawingToolExecute();
}
}
///
/// Handles the MouseMove event of the MainGrid control.
///
/// The source of the event.
/// The instance containing the event data.
private void MainGrid_MouseMove(object sender, MouseEventArgs e)
{
if (CurrentDrawingTool != null)
{
SetDrawingTool(CurrentDrawingTool);
}
else
{
DrawingToolExecute();
}
//Console.WriteLine("鼠标移动开始:" + startTime);
//timer.IsEnabled = false;
//startTime = DateTime.Now;
//timer.IsEnabled = true;
}
///
/// Pane工具相当于移动时间滑块
///
/// The instance containing the event data.
private void MoveChartPane(MouseEventArgs e)
{
DateTime desiredEndDate = DateScaler.DesiredEndDate;
float num = DateScaler.XforDate(_crossDateTime);
var num2 = (float)(_crossHairGrid.ActualWidth / (double)DateScaler.NumBars);
var num3 = (float)(e.GetPosition(_crossHairGrid).X - (double)num);
var num4 = checked((int)Math.Round((double)unchecked((float)DateScaler.EndDateIndex - num3 / num2)));
var count = DateScaler.Count();
bool flag = num4 >= count;
DateScaler.DesiredEndDate = flag ? DateTime.MaxValue : DateScaler.DateValue(num4);
if (!DateScaler.DesiredEndDate.Equals(desiredEndDate))
{
Refresh();
}
}
///
/// 清除图表容器,切换周期时使用
///
private void ChangePanesClear()
{
_chartPanes.Clear();
_chartPanesGrid.Children.Clear();
_chartPanesGrid.RowDefinitions.Clear();
}
///
/// Called when [cycle type changed].
///
/// if set to true [refresh now].
/// 是否是从分时图中切换
private void OnCycleTypeChanged(bool refreshNow, bool isFromTimesharing = false)
{
if (CurrentGoods == null) return;
var cycleType = CycleType;
var timeSpan = CurrentTimeFrame;
var goods = CurrentGoods;
var maxLoadRecordCount = MaxLoadRecordCount;
Dispatcher.BeginInvoke(new Action(() =>
{
DataSet = new ChartDataSet();
switch (cycleType)
{
case CycleType.TimeSharing:
ChangePanesClear();
DateChartSlider.Visibility = Visibility.Collapsed;
_downloadMoreButton.Visibility = Visibility.Collapsed;
OpenTimeSharePlot(CurrentGoods);
_timeSharingTimer.Start(); //开始定时器补数据
SetDatesAndRefresh(refreshNow);
break;
case CycleType.Tik:
ChangePanesClear();
// DateChartSlider.Visibility = Visibility.Collapsed;
DateChartSlider.Visibility = Visibility.Visible;
_downloadMoreButton.Visibility = Visibility.Collapsed;
_timeSharingTimer.Stop();
CreateTikChart(CurrentGoods);
SetDatesAndRefresh(refreshNow);
break;
default:
////数据源更改,计算涨幅
if (isFromTimesharing)
{
ChangePanesClear();
foreach (var chartPane in _chartCachePanes)
{
//取最大grid高度做*
var stars = _chartPanesGrid.RowDefinitions.Count > 0
? _chartPanesGrid.RowDefinitions.Max(z => z.Height.Value)
: 1.0;
AddChartPane(chartPane, stars, IsMainChartPane(chartPane));
}
}
//CreateMinuteChart(CurrentGoods);
_timeSharingTimer.Stop();
DateChartSlider.Visibility = Visibility.Visible;
DataSet.DataPoints = CaclulateCycleDataIncrease(OnLoadHistoryCycleData(goods, cycleType, timeSpan, maxLoadRecordCount, DateTime.Now));
SetDatesAndRefresh(refreshNow);
break;
}
}), DispatcherPriority.Background);
}
///
/// 设置日期和刷新.
///
/// if set to true [refresh now].
private void SetDatesAndRefresh(bool refreshNow,bool isupdateBar=true)
{
Dispatcher.BeginInvoke(new Action(() =>
{
var allDateScaler = (AllDateScaler)DateScaler;
allDateScaler.SetDates(DataSet.DataPoints, CurrentTimeFrame, false);
//numBars为矩形柱间距,矩形柱数量实际要-1
if (isupdateBar)
{
allDateScaler.NumBars = RecordCountInternal - 1;
}
// if (refreshNow) Refresh(true);
if (DataSet.DataPoints != null && DataSet.DataPoints.Any())
{ Refresh(refreshNow); }
}), DispatcherPriority.Background);
}
///
/// Cycles the type property changed.
///
/// 是否是从分时图中切换
private void CycleTypePropertyChanged(bool isFromTimesharing)
{
Dispatcher.BeginInvoke(new Action(() =>
{
if (CycleType.TimeSharing == CycleType)
{
_chartCachePanes.Clear();
foreach (var chartPane in _chartPanes)
{
if (!chartPane.IsTimeSpaning)
{
_chartCachePanes.Add(chartPane);
}
}
}
if (_comparisonGoodsList == null || !_comparisonGoodsList.Any())
{
OnCycleTypeChanged(true, isFromTimesharing);
}
else
{
OnCycleTypeChanged(false, isFromTimesharing);
//刷新叠加商品
RefreshComparsionGoods();
}
//更新底部快捷周期状态
// TimeSpanPicker.UpdateCyleType(CycleType);
}), DispatcherPriority.Background);
}
///
/// Called when [load goods data].
///
/// The goods.
/// The total count.
/// The end time.
/// ChartDataSet.
private List OnLoadHistoryCycleData(GoodsInfo goods, CycleType cycleType, TimeSpan timeSpan, int totalCount, DateTime endTime)
{
List result = null;
var cycleTypeHandler = LoadHistoryCycleDataByCycleType;
if (cycleTypeHandler != null)
{
result = cycleTypeHandler(goods.ExchangeCode, goods.GoodsCode, cycleType, timeSpan,
DateTime.MinValue, endTime, totalCount);
}
//集合都要按时间顺排序,才能画图
return result == null ? null : result.OrderBy(z => z.Date).ToList();
}
///
/// 获取分时图的数据分钟数据
///
/// The goods.
/// The total count.
/// 开始时间
/// The end time.
/// ChartDataSet.
private List OnLoadHistoryTimeSpaningCycleData(GoodsInfo goods, int totalCount,
DateTime startTime, DateTime endTime)
{
List result = null;
var cycleTypeHandler = LoadHistoryCycleDataByCycleType;
if (cycleTypeHandler != null)
{
result = cycleTypeHandler(goods.ExchangeCode, goods.GoodsCode, CycleType.Minute, CurrentTimeFrame, startTime,
endTime, totalCount);
}
//集合都要按时间顺排序,才能画图
return result == null ? null : result.OrderBy(z => z.Date).ToList();
}
///
/// 更改时间间隔后执行
///
/// Type of the cycle.
private void OnTimeSpanChanged(CycleType cycleType)
{
DateScaler.DesiredEndDate = DateTime.MaxValue; //必须设为最大值
CycleType = cycleType;
}
///
/// 设置当前画线工具,并处理它与图例间的变动
///
///
private void SetDrawingTool(IDrawingTool aDrawing)
{
CurrentDrawingTool = aDrawing;
DrawingToolExecute();
var chartPanes = AllPanes();
foreach (var chartPane in chartPanes)
{
chartPane.OnDrawing();
}
}
///
/// 显示当前时间的报价牌
///
/// A date.
private void ShowQuoteBoard(DateTime aDate)
{
if (_pointerPopup.IsOpen && !aDate.Equals(DateTime.MinValue))
{
var list = new List();
ControlPair controlPair = null;
var controlPair2 = new ControlPair();
var textBlock = new TextBlock
{
Text = aDate.ToString("yyyy-MM-dd ddd HH:mm:ss"),
//aDate.ToString(aDate.TimeOfDay.Ticks == 0L ? "yyyy-MM-dd ddd" : "yyyy-MM-dd ddd hh:mm:ss"),
Foreground =
IsDarkBackground
? (new SolidColorBrush(Colors.White))
: (new SolidColorBrush(Colors.Black)),
HorizontalAlignment = HorizontalAlignment.Center
};
controlPair2.ControlLeft = textBlock;
list.Add(controlPair2);
var panes = AllPanes();
foreach (var current in panes)
{
bool flag = false;
var scaleLayers = current.AllScaleLayers;
if (scaleLayers != null && scaleLayers.Any())
{
foreach (var scaleLayer in scaleLayers)
{
var allFormulas = new List(scaleLayer.AllDisplayFormula);
allFormulas.AddRange(scaleLayer.ComparisonFormulas);
if (!allFormulas.Any()) continue;
foreach (var formula in allFormulas)
{
//plot.PlotBase_5031(aDate, IsDarkBackground, SymbolManager.Manager().SymbolPrecision(CurrentSymbol) > 2)
var controlPairs = formula.GetControlPairs(aDate, IsDarkBackground, this.CurrentGoods.MinUnit);
if (controlPairs != null && controlPairs.Any())
{
flag = true;
if (controlPair != null)
{
list.Add(controlPair);
controlPair = null;
}
list.AddRange(controlPairs);
}
}
}
}
if (flag)
{
controlPair = new ControlPair()
{
ControlLeft = new Border()
{
Margin = new Thickness(0.0, 2.0, 0.0, 2.0),
Height = 2.0,
BorderThickness = new Thickness(1.0),
BorderBrush = new SolidColorBrush(ColorHelper.DimGray)
}
};
}
}
_pointerGrid.RowDefinitions.Clear();
_pointerGrid.Children.Clear();
int num = 0;
foreach (var current in list)
{
var rowDefinition = new RowDefinition { Height = new GridLength(1.0, 0) };
_pointerGrid.RowDefinitions.Add(rowDefinition);
if (current.ControlLeft != null)
{
current.ControlLeft.SetValue(Control.FontSizeProperty, ChartFontSize);
if (current.ControlRight == null)
{
current.ControlLeft.SetValue(Grid.RowProperty, num);
current.ControlLeft.SetValue(Grid.ColumnSpanProperty, 2);
_pointerGrid.Children.Add(current.ControlLeft);
}
else
{
current.ControlRight.SetValue(Control.FontSizeProperty, ChartFontSize);
current.ControlLeft.SetValue(Grid.RowProperty, num);
current.ControlRight.SetValue(Grid.RowProperty, num);
current.ControlRight.SetValue(Grid.ColumnProperty, 1);
_pointerGrid.Children.Add(current.ControlLeft);
_pointerGrid.Children.Add(current.ControlRight);
}
}
num++;
}
//_pointerGrid.UpdateLayout();
//左边纵坐标宽度
var buffer = GetChartPanelOffset();
if (_pointerGrid.ActualWidth + buffer > (double)_currentX)
{
_pointerPopup.HorizontalOffset = (_pointerGrid.ActualWidth + buffer);
}
else
{
_pointerPopup.HorizontalOffset = buffer;
}
}
}
#endregion Private Methods
#region 分时图
private void _timeSharingTimer_Tick(object sender, EventArgs e)
{
//todo:修改使用行情时间
var updateTime = _goodsQuoteTime.AddMinutes(1);
//var updateTime = DateTime.Now.AddSeconds(-DateTime.Now.Second);
if (DataSet == null || DataSet.DataPoints == null || !DataSet.DataPoints.Any())
{
//没有数据源无法补数据
_timeSharingTimer.Stop();
}
else
{
var lastPoint = DataSet.DataPoints[DataSet.DataPoints.Count - 1];
var dataPoint = new BarDataPoint(lastPoint.Date, lastPoint.Value); ;
var timeSpan = updateTime - dataPoint.Date;
if (timeSpan.TotalSeconds >= 60)
{
dataPoint.Date = updateTime;
dataPoint.Volume = 0;
UpdateTimeShareData(dataPoint, this.CurrentGoods.GoodsCode);
}
UpdateTimerComparisonShareing(updateTime); //定时器更新叠加数据
}
}
///
/// 定时器更新叠加商品数据
///
/// 更新时间
private void UpdateTimerComparisonShareing(DateTime updateTime)
{
if (this.ComparisionTimeShareDic != null)
{
var keyList = this.ComparisionTimeShareDic.Keys.ToList();
foreach (var goodsCodeKey in keyList)
{
if (this.ComparisionTimeShareDic[goodsCodeKey].Any())
{
var lastPoint = this.ComparisionTimeShareDic[goodsCodeKey][
this.ComparisionTimeShareDic[goodsCodeKey].Count - 1];
var dataPoint = new BarDataPoint(lastPoint.Date, lastPoint.Value); ;
var timeSpan = updateTime - dataPoint.Date;
if (timeSpan.TotalSeconds >= 60)
{
dataPoint.Date = updateTime;
UpdateComparisonData(goodsCodeKey, (IBarDataPoint)dataPoint);
}
}
}
}
}
///
/// 更新实时数据数据集
///
/// 新添加的数据
/// 更新数据的商品代码
public void UpdateTimeShareData(IBarDataPoint barDataPoint, string goodsCode)
{
if (barDataPoint == null) return;
//格式化时间
barDataPoint.Date = barDataPoint.Date.Date.AddMinutes((int)barDataPoint.Date.TimeOfDay.TotalMinutes);
this.Dispatcher.BeginInvoke(new Action(() =>
{
if (this.CurrentGoods != null && goodsCode == this.CurrentGoods.GoodsCode)
{
if (DataSet == null)
{
DataSet = new ChartDataSet();
}
if (DataSet.DataPoints == null)
{
DataSet.DataPoints = new List();
}
if (DataSet.DataPoints.Any())
{
var volData = DataSet.DataPoints[DataSet.DataPoints.Count - 1];
var timeSpan = barDataPoint.Date.AddSeconds(-barDataPoint.Date.Second) -
volData.Date.AddSeconds(-barDataPoint.Date.Second);
int count = (int)timeSpan.TotalMinutes;
if (count < 0)
{
return;
}
if (count == 0)
{
DataSet.DataPoints[DataSet.DataPoints.Count - 1] = barDataPoint;
}
else
{
if (count >= 2 && count <= 1440) //使用定时器时更新可能不会出现这情况
{
var repairPoint = DataSet.DataPoints[DataSet.DataPoints.Count - 1];
var repairBarPoint = repairPoint as IBarDataPoint;
if (repairBarPoint != null)
{
repairBarPoint.Volume = 0;
}
for (int i = 0; i < count - 1; i++)
{
DataSet.DataPoints.Add(repairBarPoint);
}
}
DataSet.DataPoints.Add(barDataPoint);
}
}
else
{
DataSet.DataPoints.Add(barDataPoint);
}
if (timeSharingFormulaModel != null)
{
timeSharingFormulaModel.UpdatePointSharing(barDataPoint);
}
}
else
{
UpdateComparisonData(goodsCode, barDataPoint);
}
Refresh(true);
}));
}
///
/// 更新叠加商品分时图
///
/// 商品代码
///
private void UpdateComparisonData(string goodsCode, IBarDataPoint barDataPoint)
{
//更新叠加分时图数据
if (ComparisionTimeShareDic.ContainsKey(goodsCode))
{
barDataPoint.Date = barDataPoint.Date.Date.AddMinutes((int)barDataPoint.Date.TimeOfDay.TotalMinutes);
ComparisionTimeShareDic[goodsCode] = ComparisionTimeShareDic[goodsCode] ?? new List();
if (ComparisionTimeShareDic[goodsCode].Any())
{
var volData = ComparisionTimeShareDic[goodsCode][ComparisionTimeShareDic[goodsCode].Count - 1];
var timeSpan = barDataPoint.Date.AddSeconds(-barDataPoint.Date.Second) -
volData.Date.AddSeconds(-barDataPoint.Date.Second);
int count = (int)timeSpan.TotalMinutes;
if (count < 0)
{
return;
}
else if (count == 0)
{
ComparisionTimeShareDic[goodsCode][ComparisionTimeShareDic[goodsCode].Count - 1] = barDataPoint;
}
else
{
if (count >= 2 && count <= 1440) //使用定时器时更新可能不会出现这情况
{
var repairPoint = ComparisionTimeShareDic[goodsCode][ComparisionTimeShareDic[goodsCode].Count - 1];
for (int i = 0; i < count - 1; i++)
{
ComparisionTimeShareDic[goodsCode].Add(repairPoint);
}
}
ComparisionTimeShareDic[goodsCode].Add(barDataPoint);
}
}
else
{
ComparisionTimeShareDic[goodsCode].Add(barDataPoint);
}
if (this._comparisonFommulaHsSet != null && _comparisonFommulaHsSet.ContainsKey(goodsCode))
{
_comparisonFommulaHsSet[goodsCode].UpdateComparsionPoint(barDataPoint);
}
}
}
///
/// 更新单笔数据
///
/// tik数据
///
public void UpdateTikData(IBarDataPoint barDataPoint, string goodsCode)
{
if (barDataPoint == null) return;
if (this.CurrentGoods != null && goodsCode == this.CurrentGoods.GoodsCode)
{
if (DataSet == null)
{
DataSet = new ChartDataSet();
}
if (DataSet.DataPoints == null)
{
DataSet.DataPoints = new List();
}
DataSet.DataPoints.Add(barDataPoint);
if (_tikFormulaModel != null)
{
_tikFormulaModel.UdpdateTickPoint(barDataPoint);
Refresh(true);
}
}
}
///
/// 更新单笔数据
///
public void UpdateMinuteData(IBarDataPoint barDataPoint, string goodsCode)
{
DataSet.DataPoints = CaclulateCycleDataIncrease(OnLoadHistoryCycleData(CurrentGoods, CycleType, CurrentTimeFrame, MaxLoadRecordCount, DateTime.Now));
SetDatesAndRefresh(true);
}
///
/// 设置分时图当前点的数量
///
/// 当前数量
private int SetCountPoint()
{
if (CurrentGoods == null || CurrentGoods.OpenCloseTimes == null) return 0;
var timeSpan = TimeSpan.Zero;
foreach (var openCloseTime in CurrentGoods.OpenCloseTimes)
{
timeSpan += openCloseTime.CloseTime - openCloseTime.OpenTime;
}
var count = (int)timeSpan.TotalMinutes + CurrentGoods.OpenCloseTimes.Count; //加上每段时间需加1
_timeSharingMaxPointCount = count;
return count;
}
///
/// 打开分时图
///
/// 分时图商品
public void OpenTimeSharePlot(GoodsInfo goodsInfo)
{
var pane = new ChartPane(this, true);
//取最大grid高度做*
var stars = _chartPanesGrid.RowDefinitions.Count > 0
? _chartPanesGrid.RowDefinitions.Max(z => z.Height.Value)
: 1.0;
AddChartPane(pane, stars);
SetCountPoint();
var getEndDatatime = DateTime.Now;
var startDateTime = DateTime.Now.Date;
if (CurrentGoods.OpenCloseTimes != null &&
CurrentGoods.OpenCloseTimes.Any()) //取当前开收市时间
{
getEndDatatime = CurrentGoods.OpenCloseTimes[CurrentGoods.OpenCloseTimes.Count - 1].CloseTime;
startDateTime = CurrentGoods.OpenCloseTimes[0].OpenTime;
}
DataSet.DataPoints = OnLoadHistoryTimeSpaningCycleData(CurrentGoods, _timeSharingMaxPointCount, startDateTime,
getEndDatatime);
// GetComparisonDataSet(_timeSharingMaxPointCount, startDateTime, getEndDatatime);
//OnLoadHistoryTimeSpaningCycleData(CurrentGoods, _timeSharingMaxPointCount, startDateTime, getEndDatatime);
var scaleLayer = new ScaleLayer();
var displayFormula = new DisplayFormula(DataSet, this, goodsInfo)
{
OpenTime = startDateTime,
CloseTime = getEndDatatime,
};
timeSharingFormulaModel = displayFormula;
scaleLayer.AllDisplayFormula.Add(displayFormula);
displayFormula.ScaleLayer = scaleLayer;
displayFormula.IsTimeShare = true;
pane.AddScaleLayer(scaleLayer);
var plots = new List();
foreach (var indicator in displayFormula.FormulaModel.IndicatorList)
{
if (!indicator.VolBar) //是否为成交量
{
var linePlot = new LinePlot(indicator, this) { ScaleLayer = scaleLayer };
scaleLayer.AllPlots.Add(linePlot);
plots.Add(linePlot);
}
else
{
//成交量显示在下方
//var volScaleLayer = new ScaleLayer();
//var volpane = new ChartPane(this);
////取最大grid高度做*
//var start = _chartPanesGrid.RowDefinitions.Count > 0
// ? _chartPanesGrid.RowDefinitions.Max(z => z.Height.Value)
// : 1.0;
//AddChartPane(volpane, start);
//volpane.AddScaleLayer(volScaleLayer);
//var linePlot = new LinePlot(indicator, this);
//volScaleLayer.AllPlots.Add(linePlot);
//linePlot.ScaleLayer = volScaleLayer;
//plots.Add(linePlot);
}
}
//添加叠加分时图
GetComparisonDataSet(_timeSharingMaxPointCount, startDateTime, getEndDatatime, scaleLayer);
displayFormula.PlotBases = plots;
// DrawingTimeShareChart();
}
///
/// 显示即时图
///
/// 商品
public void CreateTikChart(GoodsInfo goodsInfo)
{
var pane = new ChartPane(this);
//取最大grid高度做*
var stars = _chartPanesGrid.RowDefinitions.Count > 0
? _chartPanesGrid.RowDefinitions.Max(z => z.Height.Value)
: 1.0;
AddChartPane(pane, stars);
var getEndDatatime = DateTime.Now;
var startDateTime = DateTime.Now.Date;
if (CurrentGoods.OpenCloseTimes != null &&
CurrentGoods.OpenCloseTimes.Any()) //取当前开收市时间
{
getEndDatatime = CurrentGoods.OpenCloseTimes[CurrentGoods.OpenCloseTimes.Count - 1].CloseTime;
startDateTime = CurrentGoods.OpenCloseTimes[0].OpenTime;
}
DataSet.DataPoints = OnLoadHistoryTimeSpaningCycleData(CurrentGoods, _timeSharingMaxPointCount, startDateTime,
getEndDatatime);
var scaleLayer = new ScaleLayer();
var formula = DisplayFormula.CreateTikChartFormula(this, goodsInfo, DataSet.DataPoints);
scaleLayer.AllDisplayFormula.Add(formula);
formula.ScaleLayer = scaleLayer;
pane.AddScaleLayer(scaleLayer);
_tikFormulaModel = formula;
var plots = new List();
foreach (var indicator in formula.FormulaModel.IndicatorList)
{
var linePlot = new LinePlot(indicator, this) { ScaleLayer = scaleLayer };
scaleLayer.AllPlots.Add(linePlot);
plots.Add(linePlot);
}
formula.PlotBases = plots;
}
///
/// 获取叠加商品数据
///
/// 取数据量
/// 开始时间
/// 结束时间
private void GetComparisonDataSet(int dataCount, DateTime startTime, DateTime endDateTime, ScaleLayer comparisonLayer)
{
ComparisionTimeShareDic.Clear();
_comparisonFommulaHsSet.Clear();
if (_comparisonGoodsList == null) return;
foreach (var goodseItem in _comparisonGoodsList)
{
var lineDataList = OnLoadHistoryTimeSpaningCycleData(goodseItem, dataCount, startTime,
endDateTime);
ComparisionTimeShareDic[goodseItem.GoodsCode] = lineDataList;
}
var formulas = DisplayFormula.TimeSharingFormulas(_comparisonGoodsList, this, ComparisionTimeShareDic);
foreach (var displayFormula in formulas)
{
CreateComparisonPlot(displayFormula, comparisonLayer);
}
}
///
///创建图形,添加到层中
///
/// 公式模型
/// 公式层
private void CreateComparisonPlot(DisplayFormula displayFormula, ScaleLayer comparisonLayer)
{
displayFormula.PlotBases = new List();
_comparisonFommulaHsSet[displayFormula.ComparionGoodsInfo.GoodsCode] = displayFormula;
comparisonLayer.ComparisonFormulas.Add(displayFormula);
foreach (var indicator in displayFormula.FormulaModel.IndicatorList)
{
var linePlot = new ComparisonPlot(indicator, this, displayFormula.ComparionGoodsInfo) { ScaleLayer = comparisonLayer };
linePlot.IsActive = true;
comparisonLayer.AllPlots.Add(linePlot);
displayFormula.PlotBases.Add(linePlot);
}
}
#endregion
#region 指标
///
/// 设置当前公式参数
///
public void SetCurrectFormulaParam()
{
if (this._chartPanes != null && _chartPanes.Any())
{
var scaleLayers = new List();
var displayFormulas = new List();
foreach (var chartPane in _chartPanes)
{
if (chartPane.AllScaleLayers != null
&& chartPane.AllScaleLayers.Any())
{
scaleLayers.AddRange(chartPane.AllScaleLayers);
}
}
foreach (var scaleLayer in scaleLayers)
{
if (scaleLayer.AllDisplayFormula != null && scaleLayer.AllDisplayFormula.Any())
{
displayFormulas.AddRange(scaleLayer.AllDisplayFormula);
}
}
if (displayFormulas.Any())
{
var formulaModels = displayFormulas.Select((displayFormula) => displayFormula.FormulaModel).ToList();
var programModels = formulaModels.Select((formulaModel) => formulaModel.EditProgram).ToList();
programModels = programModels.Where((model) => model != null).ToList();
var paramsSetPage = new ParamsSetPage(programModels);
var program = paramsSetPage.ShowDialog();
if (program.HasValue && program.Value == true) //更新图表
{
foreach (var displayFormula in displayFormulas) //设置公式参数
{
displayFormula.FormulaModel.SetParamValue();
displayFormula.Calculation();
}
this.Refresh(true);
}
}
}
}
///
/// 打开公式编辑器
///
public void OpenFormulEditer()
{
if (this._chartPanes != null && _chartPanes.Any())
{
var scaleLayers = new List();
var displayFormulas = new List();
foreach (var chartPane in _chartPanes)
{
if (chartPane.AllScaleLayers != null
&& chartPane.AllScaleLayers.Any())
{
scaleLayers.AddRange(chartPane.AllScaleLayers);
}
}
foreach (var scaleLayer in scaleLayers)
{
if (scaleLayer.AllDisplayFormula != null && scaleLayer.AllDisplayFormula.Any())
{
displayFormulas.AddRange(scaleLayer.AllDisplayFormula);
}
}
if (displayFormulas.Any())
{
var formulaModels = displayFormulas.Select((displayFormula) => displayFormula.FormulaModel).ToList();
var programModels = formulaModels.Select((formulaModel) => formulaModel.EditProgram).ToList();
programModels = programModels.Where((model) => model != null).ToList();
var vm = new EditFormulaViewModel(programModels);
vm.OpenEditer();
foreach (var displayFormula in displayFormulas) //设置公式参数
{
displayFormula.FormulaModel.SetParamValue();
displayFormula.Calculation();
}
this.Refresh(true);
}
}
}
///
/// 清除主图中指标
///
public void ClearMainPaneIndicator()
{
var pane = GetMainChartPane();
if (pane != null)
{
foreach (var scaleLayer in pane.AllScaleLayers)
{
scaleLayer.ClearFormulas();
}
this.Refresh();
}
}
///
/// 通过名称添加指标
///
/// 指标名称
/// 是否立刻刷新图表
public void AddIndicatorByName(string formulaName, bool refresh = true)
{
var formula = FormulaHelper.GetFormulaByName(formulaName, string.Empty);
if (formula != null)
{
var displayFormula = new DisplayFormula(formula, DataSet, this);
AddFormulaFromPane(displayFormula);
displayFormula.SetSource(DataSet, false);
if (refresh)
{
Refresh(true);
}
}
}
///
/// 添加指标
///
/// 指标配置
public void AddIndicator(ProgramModel program)
{
var formulaModel = program.CovertToFormulaModel();
var displayFormula = new DisplayFormula(formulaModel, DataSet, this);
AddFormulaFromPane(displayFormula);
displayFormula.SetSource(DataSet, false);
Refresh(true);
}
#endregion
#endregion Methods
}
}