User control likes Google Financial Chart V1.0

UI:

1.Display current indexes

2.Ellipses of current selected node (Select node by move mouse) 

3.Move 3 to show details of selected days

4. Backend Code

/// <summary>
    /// Interaction logic for CitiFinancialChart.xaml
    /// </summary>
    public partial class FinancialChart : UserControl
    {
       
        public FinancialChart()
        {
            InitializeComponent();
        }

        Action<object> displayItem;

        Dictionary<string,Ellipse> ellipses=null ;
        Dictionary<string, ChartSeries> serieses = null;
        Dictionary<string, TextBlock> titles = null;
        public void SetChartData(IEnumerable data, Dictionary<string, string> seriesNamePathPairs,
            string xAxisPath,
            string yAxisHeader,
            Action<object> _displayItem)
        {
            displayItem = _displayItem;
            canvas .Children .Clear();
            ellipses=new Dictionary<string,Ellipse>();
            titles = new Dictionary<string, TextBlock>();
            serieses = new Dictionary<string, ChartSeries>();
            area.Series.Clear();
            stck.Children.Clear();
            foreach(var kvp in seriesNamePathPairs)
            {
                Ellipse ellipse=new Ellipse();
                ellipse .Width =5;
                ellipse .Height =5;
                ellipse.Visibility = System.Windows.Visibility.Collapsed ;
                ellipses.Add(kvp.Key ,ellipse);
                canvas.Children.Add(ellipse);

                TextBlock txt = new TextBlock();
                stck.Children.Add(txt);
                titles.Add(kvp.Key, txt);

                ChartSeries series = new ChartSeries();
                series.ShowToolTip = false;
                series.BindingPathX = xAxisPath;
                series.BindingPathsY = new string[]{ kvp.Value};
                series.Type = ChartTypes.Line;
                Binding binding = new Binding();
                binding.ElementName = "timelineControl";
                binding.Path = new PropertyPath("SelectedData", null);
                binding.Mode = BindingMode.TwoWay;
                binding.UpdateSourceTrigger = UpdateSourceTrigger.Explicit;
                series.SetBinding(ChartSeries.DataSourceProperty, binding);
                area.Series.Add(series);
                serieses.Add(kvp.Key, series);
            }
           
            this.yAxisHeader.Text = yAxisHeader;
            timelineControl.HoldUpdate = true;
            timelineControl.PrimaryAxis.DateTimeInterval = new TimeSpan(268, 0, 0, 0);
            timelineControl.DataSource = data ;
            timelineControl.BindingPathX = xAxisPath;
            timelineControl.BindingPathsY = seriesNamePathPairs.Values .ToArray(); 
            timelineControl.HoldUpdate = false;
            timelineControl.EndInit();
            DataContext = data;
            area.MouseMove += new System.Windows.Input.MouseEventHandler(area_MouseMove);
            area.MouseEnter += new System.Windows.Input.MouseEventHandler(area_MouseEnter);
            area.MouseLeave += new System.Windows.Input.MouseEventHandler(area_MouseLeave);
        }

        void area_MouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
        {
            foreach (var el in ellipses)
                el.Value.Visibility = System.Windows.Visibility.Collapsed; 
        }

        void area_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
        {
            foreach (var el in ellipses)
                el.Value.Visibility = System.Windows.Visibility.Visible ;
        }

        void area_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
        {
            ChartArea area = sender as ChartArea;
            IChartDataPoint currentChartPoint=null ;
            foreach (var el in ellipses)
            {
                el.Value.Fill = serieses[el.Key].Interior;
                MoveEllipse(area, canvas
                , serieses[el.Key].Data , e, el.Value , out currentChartPoint);
                if (currentChartPoint != null)
                {
                    titles[el.Key].Text = " " + el.Key + ":" + currentChartPoint.Y;
                    titles[el.Key].Foreground = el.Value.Fill;
                }
            }

            if (displayItem != null && currentChartPoint != null)
            {
                displayItem(currentChartPoint.Item);
            }
             
        }

        void MoveEllipse(ChartArea area, Canvas canvas, IChartData chartData, System.Windows.Input.MouseEventArgs e, Ellipse ellipse, out IChartDataPoint currentChartPoint)
        {
            //Get mouse position related with chart area
            Point mousePointOnChartArea = e.GetPosition(area);
            //Get xAxis Value and Round value
            double xValue = area.PointToValue(area.PrimaryAxis, mousePointOnChartArea), yValue;
            double xRoundValue = Math.Round(xValue);

            //Wrapper ChartData to use Linq 
            EnumerableChartData data = new EnumerableChartData(chartData);

            //Get Current chart point
            currentChartPoint = data.FirstOrDefault(x => x.X == xRoundValue);
            if (currentChartPoint == null)
                return;



            // Get next Chart point statisfied xValue betweens nextChartPoint.X and currentChartPoint.X
            IChartDataPoint nextChartPoint;
            if (xValue > xRoundValue)
                nextChartPoint = data.OrderBy(x => x.X).FirstOrDefault(x => x.X > xValue);
            else
                nextChartPoint = data.OrderBy(x => x.X).LastOrDefault(x => x.X < xValue);
            if (nextChartPoint == null)
                nextChartPoint = currentChartPoint;

            // Get Value of Y axis
            yValue = GetValueFromLinearFunction(currentChartPoint.X, currentChartPoint.Y, nextChartPoint.X, nextChartPoint.Y, xValue);
            // convert yValue to Point
            double yPoint = area.ValueToPoint(area.SecondaryAxis, yValue);
            var epc = e.GetPosition(canvas);
            ellipse.SetValue(Canvas.LeftProperty, epc.X - ellipse.Width / 2);
            ellipse.SetValue(Canvas.TopProperty, epc.Y + (yPoint - mousePointOnChartArea.Y) - ellipse.Height / 2);
            //ellipse .Fill = 
        }


        double GetValueFromLinearFunction(double x1, double y1, double x2, double y2, double x)
        {
            if (x1 == x2)
                return y1;
            return y1 + ((y2 - y1) / (x2 - x1)) * (x - x1);
        }
    }

  5.XAML

<UserControl x:Class="TimeLineControlSample.UserControls.FinancialChart"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:sync="http://schemas.syncfusion.com/wpf"
             xmlns:local="clr-namespace:TimeLineControlSample" 
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <UserControl.Resources>
        <local:LabelConverter  x:Key="LabelConverterKey" />
    </UserControl.Resources>
    <Grid>
        <Grid.RowDefinitions> 
            <RowDefinition Height="40"></RowDefinition>
            <RowDefinition Height="0.75*" />
            <RowDefinition Height="0.25*" />
        </Grid.RowDefinitions>
        
        <StackPanel Name="stck" Orientation="Horizontal" HorizontalAlignment="Right"  ></StackPanel>
        
        <Canvas Grid.Row="1" Name="canvas" Background="Transparent">
        </Canvas>
        <sync:Chart Grid.Row="1" Name="chart" >
            <sync:ChartArea Name="area">
                <sync:ChartArea.PrimaryAxis>
                    <sync:ChartAxis ValueType="DateTime"  LabelDateTimeFormat="MMM/dd/yyy">
                        <sync:ChartAxis.Header>
                            <TextBlock Text="Date" FontFamily="Segoe UI" FontSize="12"/>
                        </sync:ChartAxis.Header>
                    </sync:ChartAxis>
                </sync:ChartArea.PrimaryAxis>

                <sync:ChartArea.SecondaryAxis>
                    <sync:ChartAxis>
                        <sync:ChartAxis.Header>
                            <TextBlock Name="yAxisHeader" FontFamily="Segoe UI" FontSize="12"/>
                        </sync:ChartAxis.Header>
                    </sync:ChartAxis>
                </sync:ChartArea.SecondaryAxis> 

            </sync:ChartArea>
        </sync:Chart>

        <sync:TimeLineControl x:Name="timelineControl" Grid.Row="2"
                              StartValue="0" EndValue="85" IsContextMenuEnabled="True">

            <sync:TimeLineControl.PrimaryAxis>
                <sync:ChartAxis x:Name="primary" TickSize="0" SmallTickSize="0" RangePadding="None" EdgeLabelsDrawingMode="Fit" IntersectAction="Hide" ValueType="DateTime"  LabelDateTimeFormat="yyyy" Interval="1"  LabelPosition="Outside" LabelForeground="#FFD8F0F0" OpposedPosition="True">
                    <sync:ChartArea.ShowGridLines>False</sync:ChartArea.ShowGridLines>
                    <sync:ChartArea.ShowMajorGridLines>True</sync:ChartArea.ShowMajorGridLines>
                    <sync:ChartArea.OriginLineStroke>
                        <Pen Brush="#FF4A9BC6" Thickness="1"/>
                    </sync:ChartArea.OriginLineStroke>
                    <sync:ChartAxis.LineStroke>
                        <Pen Brush="#FF4A9BC6" Thickness="1"/>
                    </sync:ChartAxis.LineStroke>
                </sync:ChartAxis>
            </sync:TimeLineControl.PrimaryAxis>
            <sync:TimeLineControl.Axes>
                <sync:ChartAxis x:Name="quater" ValueType="DateTime">
                    <sync:ChartArea.ShowGridLines>True</sync:ChartArea.ShowGridLines>
                    <sync:ChartArea.ShowMajorGridLines>True</sync:ChartArea.ShowMajorGridLines>
                    <sync:ChartAxis.LabelTemplate>
                        <DataTemplate>
                            <TextBlock Text="{Binding Converter={StaticResource LabelConverterKey}}"/>
                        </DataTemplate>
                    </sync:ChartAxis.LabelTemplate>
                </sync:ChartAxis>
            </sync:TimeLineControl.Axes>
        </sync:TimeLineControl>
        
    </Grid>
</UserControl>

6. Test Window XMAL

<Window x:Class="TimeLineControlSample.TestCustomerControls"
        xmlns:my="clr-namespace:TimeLineControlSample.UserControls"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="TestCustomerControls" MinHeight="300" MinWidth="300">
    <Grid>
        <my:CitiFinancialChart x:Name="cfc" />
    </Grid>
</Window>

7. Test Window Backend Code

  public partial class TestCustomerControls : Window
    {
        public TestCustomerControls()
        {
            InitializeComponent();
            DataCollection collection = new DataCollection();
            cfc.SetChartData(collection.datalist,
                new Dictionary<string, string> { { "High", "High" }, { "Low", "Low" }, { "Last", "Last" } },
                "TimeStamp", "date", null);
                
        }
    }

  

原文地址:https://www.cnblogs.com/mjgb/p/2714254.html