I'm writing an application that has need of making small bitmaps of charts for static preview purposes. I've tried everything I can think of to get RenderTargetBitmap to work with XamChart, but all I get is an empty bitmap (the bitmap is the correct size, it's just filled with transparent pixels). The following code demonstrates the use of RenderTargetBitmap with a regular button and a XamChart. Both are created at run time and are never displayed. Creating a bitmap of the button works, but not XamChart. Is this a bug, or is there a workaround?
<Window x:Class="XamChartTest.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="XamChartTest" Height="300" Width="300" > <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <Button Content="XamChart Test" Click="OnClickChart" Grid.Row="0"/> <Button Content="Regular Test" Click="OnClickTest" Grid.Row="1" /> </Grid></Window>
public void OnClickChart(object sender, RoutedEventArgs e) { XamChart testChart = new XamChart(); testChart.Width = 200; testChart.Height = 200; testChart.Measure(new Size(200, 200)); testChart.Arrange(new Rect(0, 0, 200, 200)); RenderTargetBitmap bmp = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32); bmp.Render(testChart); PngBitmapEncoder png = new PngBitmapEncoder(); png.Frames.Add(BitmapFrame.Create(bmp)); using (Stream stm = File.Create(@"C:\TestChart.png")) png.Save(stm); } public void OnClickTest(object sender, RoutedEventArgs e) { Button testButton = new Button(); testButton.Content = "Test Button"; testButton.Width = 200; testButton.Height = 200; testButton.Measure(new Size(200, 200)); testButton.Arrange(new Rect(0, 0, 200, 200)); RenderTargetBitmap bmp = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32); bmp.Render(testButton); PngBitmapEncoder png = new PngBitmapEncoder(); png.Frames.Add(BitmapFrame.Create(bmp)); using (Stream stm = File.Create(@"C:\TestButton.png")) png.Save(stm); }
Hi,
Please, add the chart to the visual tree:
<Window x:Class="WpfApplication12.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:igCA="http://infragistics.com/Chart" Title="Window1" Height="300" Width="300"> <Grid> <Grid.RowDefinitions> <RowDefinition/> <RowDefinition/> </Grid.RowDefinitions> <igCA:XamChart Name="testChart" Margin="0,0,0,0" Width="200" Height="200"/> <Button Content="XamChart Test" Click="OnClickChart" Grid.Row="0"/> <Button Content="Regular Test" Click="OnClickTest" Grid.Row="1" /> </Grid></Window>
public void OnClickChart(object sender, RoutedEventArgs e) { testChart.Measure(new Size(200, 200)); testChart.Arrange(new Rect(0, 0, 200, 200));
RenderTargetBitmap bmp = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32); bmp.Render(testChart); PngBitmapEncoder png = new PngBitmapEncoder(); png.Frames.Add(BitmapFrame.Create(bmp)); using (Stream stm = File.Create(@"C:\TestChart.png")) png.Save(stm); }
Thanks,GoranS
I think perhaps I wasn't 100% clear. I don't want to display the chart when I do this, I want to make a thumbnail of the chart, keeping that chart 'off screen'. The XamChart object itself is not displayed to the user at this point, and we don't want it to be a part of the visual tree.
So, how can I get RenderTargetBitmap to work without adding the chart to the visual tree (like I'm generating the button bitmap)?
http://news.infragistics.com/forums/p/12901/48251.aspx#48251
Andrew Smith"]I took a quick look at this and using the original code snippet you provided, the wpf framework is never assigning the Template of the control so I think you are going to have to at least add it to the logical tree. I modified your code and was able to get the chart to render: XamChart testChart = new XamChart(); // the following isn't really necessary since you are arranging it with 200,200 //testChart.BeginInit(); //testChart.Width = 200; //testChart.Height = 200; //testChart.EndInit(); // the following is necessary so the wpf framework assigns the template // to the control this.AddLogicalChild(testChart); testChart.Measure(new Size(200, 200)); // the following was necessary to initialize the chart testChart.Refresh(); testChart.Arrange(new Rect(0, 0, 200, 200)); testChart.UpdateLayout(); RenderTargetBitmap bmp = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32); bmp.Render(testChart); this.RemoveLogicalChild(testChart);
I took a quick look at this and using the original code snippet you provided, the wpf framework is never assigning the Template of the control so I think you are going to have to at least add it to the logical tree. I modified your code and was able to get the chart to render:
XamChart testChart = new XamChart();
// the following isn't really necessary since you are arranging it with 200,200
//testChart.BeginInit();
//testChart.Width = 200;
//testChart.Height = 200;
//testChart.EndInit();
// the following is necessary so the wpf framework assigns the template
// to the control
this.AddLogicalChild(testChart);
testChart.Measure(new Size(200, 200));
// the following was necessary to initialize the chart
testChart.Refresh();
testChart.Arrange(new Rect(0, 0, 200, 200));
testChart.UpdateLayout();
RenderTargetBitmap bmp = new RenderTargetBitmap(200, 200, 96, 96, PixelFormats.Pbgra32);
bmp.Render(testChart);
this.RemoveLogicalChild(testChart);
I am having the same problem as the original poster. I need to render a chart as a bitmap, and adding it to the visual tree is not an option. I tried the above sample code, and it works, until you try to DataBind. Then you get nothing. I tried calling DataSourceRefresh() as well, to no avail. I have found no way to force the chart to DataBind other than to add it to the visual tree of a window, and display they window.
No solution has yet to present itself. Notice that in the example above, the button is never added to the visual tree, and yet RenderTargetBitmap works just fine (of course it relies on the WPF rendering engine, why would you even point that out?). I've used RenderTargetBitmap to successfully render bitmaps of many different kinds of controls that are never added to the visual tree, including WPF standard controls, custom controls written by myself and my team, and 3rd party controls. In many cases, you must call Measure and Arrange first in order to force layout (and sometimes UpdateLayout), and when the control is data bound you must use BeginInit and EndInit to see results. However, even when I perform all of these functions (even though this works with every other control I've tried with RenderTargetBitmap that is never added to the visual tree), I cannot get a XamChart to render, only a blank bitmap is returned. Here is the exact code I'm using:
internalChart.BeginInit(); internalChart.Width = tempChartWidth; internalChart.Height = tempChartHeight; internalChart.Measure(new Size(tempChartWidth, tempChartHeight)); internalChart.Arrange(new Rect(0, 0, tempChartWidth, tempChartHeight)); internalChart.EndInit(); internalChart.UpdateLayout();
RenderTargetBitmap bmp = new RenderTargetBitmap(tempChartWidth, tempChartHeight, 96, 96, PixelFormats.Pbgra32); bmp.Render(internalChart); PngBitmapEncoder png = new PngBitmapEncoder(); png.Frames.Add(BitmapFrame.Create(bmp)); using (Stream stm = File.Create(@"C:\TestChart.png")) png.Save(stm);
Now, obviously adding XamChart to the visual tree makes subsequent calls to RenderTargetBitmap work just fine, but that defeats the purpose of what I'm trying to do. So, given that I can render buttons, listboxes, panels, etc., using RenderTargetBitmap without ever adding those controls to the visual tree, why can I not do the same with XamChart?
Did you come up with a solution to your problem? Goran was suggesting that you add the chart to the Visual Tree because RenderTargetBitmap relies on the WPF rendering engine. If the target has not been added to the Visual Tree, it will not be drawn, which is why you were experiencing the problem.