Search code examples
c#wpfimagelivecharts

c# chart to image with LiveCharts


i have a little problem. I want to export to an image my charts. I known that is possible with the code given by beto-rodriguez (here).

But i have a problem, i can't have what i could have by displaying it in the screen. See the image above. On the bottom right, i have the image saved in png. And in the left of the image, i have the chart with all the parameters displayed where i want.

Do you known if it's possible to have the same chart (in the left) in the saved image ? Actually, i use a thread to capture (copy/paste) the image automatically.

Do you known what are the parameters i must set on to have the correct image ?

Double chart

Thanks in advance. Regards.

********************************* After edit

Sorry for my late repsonse. I try what you said but unfornately I can't made that i want. I will explain what i do: I have a class "MakeReport" who can call another class "GraphMaker" with:

MyGraph = new GraphMaker();
MyGraph = GiveAGraph(MyGraph);

And the class "MakeReport" will complete the chart with some values with the sub-program "GiveAGraph()":

GraphData.SeriesCollection.Add(new RowSeries
   {
       Title = Criteria, 
       Values = DataValues,
       ScalesYAt = Index,
       DataLabels = true
    });

End of "GiveAGRaph()".

Now I have a chart ready to display, i want to use it to make an image and for test (and debug) i show it:

// Chart to Image
MyGraph.GiveMeAnImageFromChart();      <-- to make a picture with the chart
// Show the graph
MyGraph.Show();                        <-- for debug and test, i display it.

With "MyGraph.GiveAnImageFromChart()", i don't have the same result than "MyGraph.Show()". The picture (save as png) is different to the displayed chart.

The sub-program "GiveAnImageFromChart" included in the "GraphMaker" class is :

public void GiveMeAnImageFromChart()
    {
            var viewbox = new Viewbox();
            myChart.Background = Brushes.White;
            myChart.DataContext = this;

            // myChart  il faut tout mettre en paramètres

            viewbox.Child = myChart;
            viewbox.Measure(myChart.RenderSize);
            viewbox.Arrange(new Rect(new Point(0, 0), myChart.RenderSize));

            myChart.Update(true, true); //force chart redraw
            viewbox.UpdateLayout();

            SaveToPng(myChart, "chart.png");
            //png file was created at the root directory.

    }

The "myChart" variable is public. The "SaveToPng" program used come from your example (here).

To save the picture, i try with the following method :

public System.Drawing.Bitmap ControlToImage(Visual target, double dpiX, double dpiY)
    {
        if (target == null)
        {
            return null;
        }
        // render control content
        Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
        Console.WriteLine("Bounds width = " + bounds.Width + " et bounds height = " + bounds.Height);
        RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
                                                        (int)(bounds.Height * dpiY / 96.0),
                                                        dpiX,
                                                        dpiY,
                                                        PixelFormats.Pbgra32);
        DrawingVisual dv = new DrawingVisual();
        using (DrawingContext ctx = dv.RenderOpen())
        {
            VisualBrush vb = new VisualBrush(target);
            ctx.DrawRectangle(vb, null, new Rect(new System.Windows.Point(), bounds.Size));
        }
        rtb.Render(dv);

        //convert image format
        MemoryStream stream = new MemoryStream();
        BitmapEncoder encoder = new BmpBitmapEncoder();
        encoder.Frames.Add(BitmapFrame.Create(rtb));
        encoder.Save(stream);

        return new System.Drawing.Bitmap(stream);
    }

With :

Bitmap ImageChart = MyGraph.ControlToImage(MyGraph, MyGraph.Width, MyGraph.Height);

With this method, i have an error because the "bounds.Width" and "bounds.Height" are equal to -8. And finally, i don't have any chart to convert.

I think i give a wrong "visual Target" in the "ControlImage" and I miss something but i don't know what. If you need more information, ask me. Thanks in advance for your help.

PS: sorry for my english. Don't hesitate to correct me.


Solution

  • thanks to bto-rdz, i made a solution. I found that i didn't use Livecharts correctly. So i post my code if someone need it.

    This is my GraphMaker.xaml file:

    <UserControl x:Class="MyProject.GraphMaker"
            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:local="clr-namespace:MyProject"
            mc:Ignorable="d" 
            d:DesignHeight="730" d:DesignWidth="1660">
    <Grid>
    </Grid>
    </UserControl>
    

    And my GraphMaker.xaml.cs file

        using System;
    using System.IO;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using LiveCharts;
    using LiveCharts.Wpf;
    using System.Collections.Generic;
    using System.ComponentModel;
    
    
    namespace MyProject
    {    
        public partial class GraphMaker : UserControl
        {
            // PUBLIC
            public CartesianChart MyTestChart;
            public SeriesCollection MySeriesCollection { get; set; }
            public string[] Labels { get; set; }
            public string AxisTitle { get; set; }
            public Func<double, string> YFormatter { get; set; }
            public Axis Axis1, Axis2, Axis3, Axis4, Axis5, Axis6, Axis7, Axis8, Axis9, Axis10, AxisXChart;
    
    
            public GraphMaker()
            {
                InitializeComponent();
                MySeriesCollection = new SeriesCollection();
    
                MyTestChart = new CartesianChart
                {
                    DisableAnimations = true,
                    Width = 1600,
                    Height = 700,
                    Series = MySeriesCollection
                };
    
                MyTestChart.LegendLocation = LegendLocation.Right;
    
                // *** Axis 1 ***
                Axis1 = new Axis();
                Axis1.Foreground = Brushes.DodgerBlue;
                Axis1.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis1.LabelFormatter = YFormatter;
                MyTestChart.AxisY.Add(Axis1);
    
                // *** Axis 2 ***
                Axis2 = new Axis();
                Axis2.Foreground = Brushes.IndianRed;
                Axis2.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis2.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis2);
    
                // *** Axis 3 ***
                Axis3 = new Axis();
                Axis3.Foreground = Brushes.Gold;
                Axis3.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis3.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis3);
    
                // *** Axis 4 ***
                Axis4 = new Axis();
                Axis4.Foreground = Brushes.Gray;
                Axis4.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis4.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis4);
    
                // *** Axis 5 ***
                Axis5 = new Axis();
                Axis5.Foreground = Brushes.DeepSkyBlue;
                Axis5.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis5.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis5);
    
                // *** Axis 6 ***
                Axis6 = new Axis();
                Axis6.Foreground = Brushes.HotPink;
                Axis6.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis6.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis6);
    
                // *** Axis 7 ***
                Axis7 = new Axis();
                Axis7.Foreground = Brushes.Orange;
                Axis7.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis7.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis7);
    
                // *** Axis 8 ***
                Axis8 = new Axis();
                Axis8.Foreground = Brushes.RoyalBlue;
                Axis8.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis8.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis8);
    
                // *** Axis 9 ***
                Axis9 = new Axis();
                Axis9.Foreground = Brushes.Black;
                Axis9.Position = AxisPosition.RightTop;
                Axis9.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis9);
    
                // *** Axis 10 ***
                Axis10 = new Axis();
                Axis10.Foreground = Brushes.DarkTurquoise;
                Axis10.Position = AxisPosition.RightTop;
                YFormatter = value => value.ToString("N2");
                Axis10.LabelFormatter = YFormatter;
                //MyTestChart.AxisY.Add(Axis10);
    
                AxisXChart = new Axis();
                AxisXChart.Title = AxisTitle;
                AxisXChart.Labels = Labels;
            }
    
    
            public void TakeTheChart()
            {
                var viewbox = new Viewbox();
                viewbox.Child = MyTestChart;
                viewbox.Measure(MyTestChart.RenderSize);
                viewbox.Arrange(new Rect(new Point(0, 0), MyTestChart.RenderSize));
                MyTestChart.Update(true, true); //force chart redraw
                viewbox.UpdateLayout();
    
                SaveToPng(MyTestChart, "Chart.png");
                //png file was created at the root directory.
            }
    
            public void SaveToPng(FrameworkElement visual, string fileName)
            {
                var encoder = new PngBitmapEncoder();
                EncodeVisual(visual, fileName, encoder);
            }
    
            private static void EncodeVisual(FrameworkElement visual, string fileName, BitmapEncoder encoder)
            {
                var bitmap = new RenderTargetBitmap((int)visual.ActualWidth, (int)visual.ActualHeight, 96, 96, PixelFormats.Pbgra32);
                bitmap.Render(visual);
                var frame = BitmapFrame.Create(bitmap);
                encoder.Frames.Add(frame);
                using (var stream = File.Create(fileName)) encoder.Save(stream);
            }
        }
    }
    

    Hope to help you.

    Have a nice day. Bye.