We are doing some customization on UpdateLayout on xamlChart (i.e. adding custom marker, changing rectangle color etc) and reason we chose UpdateLayout (vs Loaded) beuacse out usercontrol will be NOT be rendered on the screen but will be printed directly to XPS document (which further means no Loaded event will be called) It seems some of our customization doesn't seem to be working in this way, but if display the user control on screen, everything seems to be working i.e. Markers are properly aligned, Y-axis scale is correctly formatted using converter on DataTemplate on YAxisNumeric Label.
This would mean there is some post rendering is happening during/after load event
I was wondering if we could subscribe any event which marks the end of entire rendering
The issue with the chart being hard to print is something we are addressing in the next volume release. In the meantime there are some work arounds. I will get back to you.
Well, the issue is not pertaining to printing at all, may be I didn't put it right.
As part of our requirement, we are not rendering the chart on screen but directly into the XPS document, which has been working perfectly all right, including infragistic charts(we have been using other bunch of third party controls and our own custom controls)
As part of chart development, we have to add few more customization than what currently being offered from xamlChart e.g. Changing rectangle color based on value, position and other view model attributes.The solution which provided to us is not good enough to handle all these possible scenarios ( http://forums.infragistics.com/forums/p/51914/273825.aspx#273825) so we end up subscribing updateLayout event and using Series.RootCanvas, accessed the rectangle object model and directly manipulating it. So far so good.... but as part of other requirement we have to customize the Y axis scaling, so we added following converter
<ig:NumericYAxis.Label>
<DataTemplate>
<TextBlock Text="{Binding Item,Converter={StaticResource AxisConverter}}" />
</DataTemplate>
</ig:NumericYAxis.Label>
But this doesn't work since we are overriding updateLayout for rectangle customization. If we comment out updateLayout, this converter does work. We found similar issue, when we have to add our own custom markers
This further leads us to the conclusion that some kind of post rendering must be happening after Load (or during the async callback of certain dependency properties), so we were wondering if there is a event we could subscribe which would be fired when all the rendering is completed.
I understand this is not a usual situation, but please do let us know if you need any specific example, sample project, in order to isolate the issue
thanks
-Subhash
Making changes in response to LayoutUpdated will require you to wait for an additional LayoutUpdated event to fire, as your changed require the Layout to be updated again. Also, certain configurations of the chart in the current version cause it to not be fully ready when the first LayoutUpdated is fired. This mostly relates to auto-extents on axes, so you can avoid having to wait through additional LayoutUpdates by setting the extent of the axis labels manually. Here is an example of capturing an image after turning a column red using the current version of the chart.
The xaml:
<Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <Image x:Name="img" Width="500" Height="500" /> <Button Grid.Row="1" Content="Click" x:Name="click" Click="click_Click" /> </Grid>
And the code behind:
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); } private XamDataChart _chart; private void click_Click(object sender, RoutedEventArgs e) { _count = 0; var data = new TestData(); //var chart = new Button() { Content = "hi" }; var chart = new XamDataChart(); _chart = chart; chart.Width = 500; chart.Height = 500; chart.Axes.Add(new NumericYAxis()); chart.Axes.Add(new CategoryXAxis() { ItemsSource = data, Label = "{Label}" }); chart.Series.Add(new ColumnSeries() { ItemsSource = data, ValueMemberPath = "Value", YAxis = (NumericYAxis)chart.Axes[0], XAxis = (CategoryXAxis)chart.Axes[1] }); chart.Measure(new Size(500, 500)); chart.Arrange(new Rect(0, 0, 500, 500)); chart.UpdateLayout(); chart.LayoutUpdated += new EventHandler(chart_LayoutUpdated); } private int _count = 0; IEnumerable<DependencyObject> Visuals(DependencyObject t) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(t); i++) { var child = VisualTreeHelper.GetChild(t, i); yield return child; foreach (var subChild in Visuals(child)) { yield return subChild; } } } void chart_LayoutUpdated(object sender, EventArgs e) { switch (_count) { case 0: //chart isn't ready break; case 1: MakeFirstRed(); break; case 2: RenderTargetBitmap bmp = new RenderTargetBitmap(500, 500, 96, 96, PixelFormats.Pbgra32); bmp.Render(_chart); img.Source = bmp; _chart.LayoutUpdated -= chart_LayoutUpdated; break; } _count++; } private void MakeFirstRed() { var rect = Visuals(_chart.Series[0]).OfType<Rectangle>().Last(); rect.Fill = new SolidColorBrush(Colors.Red); } } public class TestData : ObservableCollection<TestDataItem> { public TestData() { Add(new TestDataItem() { Label = "A", Value = 1 }); Add(new TestDataItem() { Label = "B", Value = 2 }); Add(new TestDataItem() { Label = "C", Value = 3 }); Add(new TestDataItem() { Label = "D", Value = 4 }); } } public class TestDataItem { public string Label { get; set; } public double Value { get; set; } }
Hope this helps!-Graham