Reputation: 458
i want to export each chart from the grid to a image file in the system. below is the code for xaml and c#. Issue is that, wen i export, only 1st chart is getting properly export, but the second chart is not getting export, it does not map on 2nd chart to export. below is screen shots.
XAML:
<TabItem x:Name="Charts" Header="Company Charts " TabIndex="0" IsSelected="True">
<ScrollViewer ScrollViewer.VerticalScrollBarVisibility="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" Background="Transparent" telerik:StyleManager.Theme="Expression_Dark">
<Grid>
<Grid x:Name="ChartGrid" Margin="10" Background="Black">
<Grid.Resources>
<telerik:RadContextMenu x:Key="context" Width="100" telerik:StyleManager.Theme="Expression_Dark">
<telerik:RadContextMenu.Background>
<LinearGradientBrush EndPoint="0.5,1" MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="#FF515151" Offset="0.021"/>
<GradientStop Color="#FF212020" Offset="0.979"/>
<GradientStop Color="#FF222121" Offset="0.115"/>
</LinearGradientBrush>
</telerik:RadContextMenu.Background>
<telerik:RadMenuItem Header="View Data" Foreground="White" Command="{Binding ViewData}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}" telerik:StyleManager.Theme="Expression_Dark"></telerik:RadMenuItem>
<telerik:RadMenuItem Header="Edit Chart" Foreground="White" Command="{Binding EditChartCmd}" CommandParameter="{Binding RelativeSource={RelativeSource Self}}" telerik:StyleManager.Theme="Expression_Dark"></telerik:RadMenuItem>
</telerik:RadContextMenu>
<DataTemplate x:Key="EmptyContentTemplate">
<StackPanel Orientation="Horizontal">
<TextBlock Text="N.A." Margin="5,15,0,0" VerticalAlignment="Center" Height="30" Foreground="{Binding LabelFG}"></TextBlock>
</StackPanel>
</DataTemplate>
<!--<DataTemplate x:Key="LegendOrientation">
<StackPanel Orientation="Horizontal" />
</DataTemplate>-->
</Grid.Resources>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
</Grid>
</Grid>
</ScrollViewer>
</TabItem>
C# CODE:
private void ExportCHARTtoBMP(RadCartesianChart chartx, string p)
{
chartx.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity));
int chartW = (int)Math.Round(chartx.ActualWidth);
int chartH = (int)Math.Round(chartx.ActualHeight);
chartW = chartW == 0 ? 1 : chartW;
chartH = chartH == 0 ? 1 : chartH;
RenderTargetBitmap rtbmp = new RenderTargetBitmap(chartW + 32, chartH + 20, 96d, 96d, PixelFormats.Default);
rtbmp.Render(chartx);
BmpBitmapEncoder encoder = new BmpBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(rtbmp));
FileStream chartFS = File.Create(tempPath + "" + p + ".bmp");
encoder.Save(chartFS);
chartFS.Close();
rtbmp.Clear();
}
private void charttoimageprocess(List<string> axisdata1, List<string> axisdata2)
{
for (int row = 0; row < (chartgridimage.RowDefinitions.Count()); row++)
{
for (int column = 0; column < chartgridimage.ColumnDefinitions.Count(); column++)
{
RadCartesianChart chart = chartgridimage.ChildrenOfType<RadCartesianChart>().FirstOrDefault(e => Grid.GetRow(e) == row && Grid.GetColumn(e) == column);
chart.UpdateLayout();
chart.Arrange(new Rect(new System.Windows.Size(chart.ActualWidth, chart.ActualHeight)));
chart.UpdateLayout();
ExportCHARTtoBMP(chart, "chart" + row + "" + column);
chart_names.Add("chart" + row + "" + column + ".bmp");
StackPanel stackpan1 = chartgridimage.ChildrenOfType<StackPanel>().FirstOrDefault(e => Grid.GetRow(e) == row && Grid.GetColumn(e) == column && e.Name.Equals("stackpan1"));
Telerik.Windows.Controls.Label label1 = stackpan1.ChildrenOfType<Telerik.Windows.Controls.Label>().FirstOrDefault(e => e.Name.Equals("label1"));
StackPanel stackpan2 = chartgridimage.ChildrenOfType<StackPanel>().FirstOrDefault(e => Grid.GetRow(e) == row && Grid.GetColumn(e) == column && e.Name.Equals("stackpan2"));
Telerik.Windows.Controls.Label label2 = stackpan2.ChildrenOfType<Telerik.Windows.Controls.Label>().FirstOrDefault(e => e.Name.Equals("label2"));
axisdata1.Add(label1.Content.ToString());
axisdata2.Add(label2.Content.ToString());
if (row == 7)
{
if (column == 0)
break;
}
}
}
}
Upvotes: 3
Views: 751
Reputation: 2204
Another way to look at your question is, "why does it render the first time at all?". It looks like there are a few things that you are doing oddly with measure and arrange that may work the first time and then fail subsequent times.
If we inline ExportCHARTtoBMP
into charttoimageprocess
, we see the following snippet:
chart.UpdateLayout();
chart.Arrange(new Rect(new System.Windows.Size(chart.ActualWidth, chart.ActualHeight)));
chart.UpdateLayout();
chartx.Measure(new System.Windows.Size(double.PositiveInfinity, double.PositiveInfinity)); // from charttoimageprocess(...)
int chartW = (int)Math.Round(chartx.ActualWidth);
int chartH = (int)Math.Round(chartx.ActualHeight);
The issues here are:
Arrange
and Measure
(and often UpdateLayout
) shouldn't be called from user code unless your code is a UIElement
-derived object and you are laying out your children (this conflicts with what the Grid
is doing)Measure
and Arrange
(and UpdateLayout
) all affect layout, but don't actually render the resulting layout change.The first issue is probably your problem. If you eliminated the Arrange
/Measure
/UpdateLayout
calls above, your code would probably work fine.
The second issue may also be at play - it is possible your code is working but is invalidating the layout of the the charts, and they don't have time to re-render. Rendering in WPF happens on a separate thread from UI layout, and runs as it detects layout updates and tries to match a certain frame rate (usually 30, 60, or 120 fps). (It pauses the UI thread to run and may run during UpdateLayout sometimes). Either the first one succeeds and the others haven't finished rendering in time to display, or it uses a cached bitmap image, but the others keep getting re-laid-out (because the grid is also affected when you re-measure/arrange its children, which in turn causes it to do the same to its other children), causing each subsequent graph to try to re-render more and more times. This too would be eliminated by removing Arrange/Measure from your code above.
Finally, you might be able to circumvent all these issues by rendering the entire Grid
to a bitmap, then slice that bitmap up into 6 smaller bitmaps based on simple math (since it is divided into 3 equal-size columns and 2 equal-size rows).
Upvotes: 1