
Hello gents. I need to be able to generate a chart in code and subsequently export it as an image. I figured I could do this just using WPF even if there was no explicit support for it in Actipro Charts. I'm very close, as I have it rendering a basic chart as a PNG on my file system. Problem is that to make it work I have to set a timer, wait a random amount of time, and then run the code to export. If I try to export immediately after creation, I get an image with a border, but no data. I'm thinking it might have something to do with animations, based on the stackoverflow question that I got the render code from.
My goal is to be able to generate charts in code, then immediately obtain a MemoryStream of the PNG image of that chart, no hokey timers... Is this possible using the current Actipro Charts?
I have a fully operational project demonstrating the problem which I will send to the support email address right after creating this thread. Here is the code, however, so that others can see.
<Window x:Class="ChartToPngTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid x:Name="mainGrid">
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ActiproSoftware.Windows.Controls.Charts;
namespace ChartToPngTest
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
XYChart chart;
public MainWindow()
{
InitializeComponent();
chart = new XYChart();
chart.Width = 500;
chart.Height = 200;
chart.IsAxisBaselineVisible = true;
chart.GridLineMajorVisibility = GridLineVisibility.Y;
chart.LabelCollisionMode = LabelCollisionMode.Stacked;
var xaxis = new XYDoubleAxis();
xaxis.AreMajorTicksVisible = true;
xaxis.TickMajorInterval = 1000;
var yaxis = new XYDoubleAxis();
yaxis.AreMajorTicksVisible = true;
yaxis.TickMajorInterval = 1;
chart.XAxes.Add(xaxis);
chart.YAxes.Add(yaxis);
var ls = new LineSeries();
var lsl = new List<XvsY>();
for (int i = 0; i < 10; i++)
lsl.Add(new XvsY(i * 1000, 9 + ((double)i / 10 * (i % 2 == 0 ? 1 : -1)))); //dont ask...
ls.ItemsSource = lsl;
ls.XPath = "X";
ls.YPath = "Y";
chart.Series.Add(ls);
mainGrid.Children.Add(chart);
//WritePng(); //generates a png that looks like it has a border, but no data
this.Loaded += new RoutedEventHandler(Window1_Loaded); //waits 2 seconds, then runs WritePng()... this works.
}
System.Windows.Threading.DispatcherTimer snapshotTimer;
void Window1_Loaded(object sender, RoutedEventArgs e)
{
this.snapshotTimer = new System.Windows.Threading.DispatcherTimer();
this.snapshotTimer.Interval = TimeSpan.FromSeconds(2);
this.snapshotTimer.Tick += new EventHandler(snapshotTimer_Tick);
this.snapshotTimer.IsEnabled = true;
}
void snapshotTimer_Tick(object sender, EventArgs e)
{
this.snapshotTimer.IsEnabled = false;
WritePng();
}
private void WritePng()
{
chart.Measure(new Size(chart.Width, chart.Height));
chart.Arrange(new Rect(new Size(chart.Width, chart.Height)));
chart.UpdateLayout();
//chart.Refresh();
RenderTargetBitmap rtb = new RenderTargetBitmap((int)chart.Width, (int)chart.Height, 96, 96, PixelFormats.Pbgra32);
rtb.Render(chart);
PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(rtb));
string file = System.IO.Path.GetTempFileName() + ".png";
using (System.IO.Stream stream = System.IO.File.Create(file))
{
png.Save(stream);
}
System.Diagnostics.Process.Start(file);
}
}
struct XvsY
{
public double X { get; set; }
public double Y { get; set; }
public XvsY(double X, double Y)
: this()
{
this.X = X;
this.Y = Y;
}
}
}
Thank you,
Chris.