Pre loader

Serialization exception during export to XPS for custom annotation

Welcome to the SciChart Forums!

  • Please read our Question Asking Guidelines for how to format a good question
  • Some reputation is required to post answers. Get up-voted to avoid the spam filter!
  • We welcome community answers and upvotes. Every Q&A improves SciChart for everyone

WPF Forums | JavaScript Forums | Android Forums | iOS Forums

0
0

I have created a custom annotation for displaying averages for a selected section of the displayed data. It works fine for printing, or copying to the clipboard, or saving a BMP file without specifying a size. However, if I export to XPS or try to specify a size for the BMP, I get the following exception:

    SciChart.Charting.Common.Helpers.ExportException occurred
  HResult=0x80131500
  Message=Exception occured during serialization of the AverageAnnotation type. The Content property of the Object type cannot be processed. Please be advised that SciChart doesn't handle serialization of objects with propeties of interface type, collection type or custom type.You need to implement IXmlSerializible in such objects to have them handled properly. For more details, please check the InnerException.
  Source=SciChart.Charting
  StackTrace:
   at SciChart.Charting.Visuals.SciChartSurfaceBase.CreateCloneOfSurfaceInMemory(Size newSize)
   at SciChart.Charting.Visuals.SciChartSurface.CreateCloneOfSurfaceInMemory(Size newSize)
   at SciChart.Charting.Visuals.SciChartSurfaceBase.GE(ExportType D, Boolean I, Nullable`1 J)
   at SciChart.Charting.Visuals.SciChartSurfaceBase.ExportToFileInternal(String fileName, ExportType exportType, Boolean useXamlRenderSurface, Nullable`1 size)
   at SciChart.Charting.Visuals.SciChartSurfaceBase.ExportToFile(String fileName, ExportType exportType, Boolean useXamlRenderSurface)
   at SciChart.Charting.Common.Extensions.SciChartSurfaceExtensions.ExportToXPS(SciChartSurface surface, String filePath, Nullable`1 size)
   at Profile6.ProfileTestResultsWindow.SaveGraph() in C:\Vericom\vc5000configurator\Profile6\ProfileTestResultsWindow.xaml.cs:line 75

Inner Exception 1:
InvalidOperationException: Cannot serialize a generic type 'System.Collections.Generic.KeyValuePair`2[System.String,System.Collections.Generic.List`1[Profile6.TestResultsViewModels.AverageAnnotationViewModel+AverageInfo]]'.

I tried wrapping the Averages list in a class that implemented IXmlSerializable, but that didn’t change anything. Does anyone know what I need to do to make this work?

I tried attaching the source code in various formats, but keep getting Forbidden errors. So, I put it inline below. (The AverageAnnotation.xaml.cs is the default code with only InitializeComponent();)

AverageAnnotation.xaml

   <sci:CustomAnnotationForMvvm x:Class="Profile6.TestResultsViewModels.AverageAnnotation"
             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:Profile6.TestResultsViewModels"
                             xmlns:localization="clr-namespace:VC5000Configurator.Localization;assembly=VC5000Configurator.Localization"
             xmlns:sci="http://schemas.abtsoftware.co.uk/scichart"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300">
    <Border BorderBrush="Black" BorderThickness="1">
        <StackPanel Background="White">
            <StackPanel.Resources>
                <ResourceDictionary>
                    <!-- Disable the highlighting for the lists -->
                    <Style TargetType="{x:Type ListViewItem}" x:Key="NoHighlight">
                        <Setter Property="Background" Value="Transparent" />
                        <Setter Property="Margin" Value="0"/>
                        <Setter Property="Padding" Value="0"/>
                        <Setter Property="Template">
                            <Setter.Value>
                                <ControlTemplate TargetType="{x:Type ListViewItem}">
                                    <ContentPresenter />
                                </ControlTemplate>
                            </Setter.Value>
                        </Setter>
                    </Style>
                </ResourceDictionary>
            </StackPanel.Resources>

            <Label Content="{x:Static localization:I18N.Averages}"
                   HorizontalAlignment="Center"
                   FontSize="12" FontWeight="Bold"/>  
            <ListView ItemsSource="{Binding Averages}" 
                      Background="Transparent"
                      ItemContainerStyle="{StaticResource NoHighlight}">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Background="Transparent">
                            <Label Content="{Binding Key}" 
                                   Visibility="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ItemsControl}, Path=DataContext.HasMultipleRuns, Converter={StaticResource FalseToCollapsedConverter}}"
                                   FontSize="10" FontWeight="Bold"/>
                            <ListView ItemsSource="{Binding Value}"
                                      ItemContainerStyle="{StaticResource NoHighlight}">
                                <ListView.ItemTemplate>
                                    <DataTemplate>
                                        <Grid Margin="10,0,0,0"
                                              Background="Transparent">
                                            <Grid.ColumnDefinitions>
                                                <ColumnDefinition Width="Auto" SharedSizeGroup="Name"/>
                                                <ColumnDefinition Width="Auto" SharedSizeGroup="Average"/>
                                            </Grid.ColumnDefinitions>
                                            <Grid.RowDefinitions>
                                                <RowDefinition Height="Auto"/>
                                            </Grid.RowDefinitions>
                                            <Label Content="{Binding SensorName}" 
                                                   Padding="0"
                                                   FontSize="10" FontWeight="Bold"
                                                   Foreground="{Binding TextBrush}"
                                                   Background="Transparent"/>
                                            <Label Content="{Binding Average}"
                                                   Padding="0"
                                                   FontSize="10" FontWeight="Bold"
                                                   Foreground="{Binding TextBrush}"
                                                   Grid.Row="0" Grid.Column="1"/>
                                        </Grid>
                                    </DataTemplate>
                                </ListView.ItemTemplate>
                            </ListView>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackPanel>
    </Border>
</sci:CustomAnnotationForMvvm>

AverageAnnotationViewModel.cs

using System;
using System.Collections.Generic;
using System.Windows.Media;
using SciChart.Charting.Model.ChartSeries;

namespace Profile6.TestResultsViewModels
{
    public class AverageAnnotationViewModel : CustomAnnotationViewModel
    {
        public override Type ViewType => typeof(AverageAnnotation);

        private List<KeyValuePair<string, List<AverageInfo>>> averages;
        public List<KeyValuePair<string, List<AverageInfo>>> Averages
        {
            get => averages;
            set
            {
                averages = value;
                OnPropertyChanged(nameof(Averages));
                OnPropertyChanged(nameof(HasMultipleRuns));
            }
        }

        public bool HasMultipleRuns => Averages.Count > 1;

        public class AverageInfo
        {
            public AverageInfo(string sensorName, double average, Color textColor)
            {
                SensorName = sensorName;
                Average = average;
                TextColor = textColor;
                TextBrush = new SolidColorBrush(TextColor);
            }

            public string SensorName { get; }
            public double Average { get; }
            public Color TextColor { get; }
            public Brush TextBrush { get; }
        }
    }
}
Version
5.0.1.11040
  • Aaron Osterwyk
    Sorry about the formatting of the code. Not sure what the problem is…
  • Andrew Burnett-Thompson
    ^^ I resolved that. You press the 001100011 button to format code blocks.
  • You must to post comments
0
0

Hi Todd,

SciChart export works like this:

  1. If you export a chart to bitmap, at the current size, we simply screenshot the chart on screen and save it.
  2. If you specify a non-default size, or you export to XPS, or you use the XamlRenderSurface then we must clone the entire chart in-memory and reconstruct it before exporting.
  3. Cloning the entire chart is done using serialisation. SciChart elements are designed to serialise and deserialise. We use this to clone the chart, then to set properties such as Width,Height and then export it.
  4. During this serialisation process if there are any properties created by you which are not serialisable then they will crash the serializer. That is why the exception message says to implement IXmlSerializable for any custom types.

The exception message says

InvalidOperationException: Cannot serialize a generic type 'System.Collections.Generic.KeyValuePair`2[System.String,System.Collections.Generic.List`1[Profile6.TestResultsViewModels.AverageAnnotationViewModel+AverageInfo]]'.

So the property in your AverageAnnotationViewModel which cannot be serialised is

public List<KeyValuePair<string, List<AverageInfo>>> Averages

You need to either mark this with the [ShouldNotSerializeAttribute] attribute to exclude it, or, you need to make your AverageAnnotationViewModel implement IXmlSerializable and implement WriteXml / ReadXml to serialise this property.

Alternatively, an easy workaround is to ensure that you perform all Exporting to bitmap at the current chart resolution. This will avoid the cloning and serialisation step entirely.

Finally, there is another second workaround. You can mark your properties as ShouldNotSerialize and then override SciChartSurface.CreateCloneOfChartInMemory

// override in SciChartSurface
protected override SciChartSurfaceBase CreateCloneOfSurfaceInMemory(Size newSize)

This is the method where we clone the chart. You can call the base to clone the chart but add on any properties you need to. E.g.

public class SciChartSurfaceEx : SciChartSurface 
{
    protected override SciChartSurfaceBase CreateCloneOfSurfaceInMemory(Size newSize) 
    {
         var cloned = (SciChartSurface)base.CreateCloneOfSurfaceInMemory(newSize);

         for(int i = 0; i < this.Annotations.Count; i++) 
         {
              if (this.Annotations[i].DataContext is AverageAnnotationViewModel)
              {
                   ((AverageAnnotationViewModel )cloned.Annotations[i].DataContext).Averages = ((AverageAnnotationsViewModel)this.Annotations[i].DataContext).Averages;
              }
         }
         return cloned;
    }
}

I haven’t tested this code but it is an example of how to copy properties from Source to Destination during the clone process which takes place in export. Ignoring the serialisation and doing it this way is probably simpler.

Let me know if this helps, and if you need further support.

Best regards,
Andrew

  • You must to post comments
0
0

I am considering applying server-side licensing for my javerScript application.

In the document below, there is a phrase “Our server-side licensing component is written in C++.”
(https://support-dev.scichart.com/index.php?/Knowledgebase/Article/View/17256/42/)

However, there is only asp.net sample code on the provided github.
(https://github.com/ABTSoftware/SciChart.JS.Examples/tree/master/Sandbox/demo-dotnet-server-licensing)

I wonder if there is a sample code implemented in C++ for server-side licensing.

Can you provide c++ sample code?
Also, are there any examples to run on Ubuntu?

  • You must to post comments
0
0

I tried overriding CreateCloneOfSurfaceInMemory() as recommended above. It still appears to be trying to serialize the Averages property, even if I mark it (and the private averages field) with the [ShouldNotSerialize] attribute. I also included the attribute on the HasMultipleRuns property since it references Averages. I also tried [XmlIgnore].

I tried to simply remove the AverageAnnotation from the Annotations list prior to calling base.CreateCloneOfSurfaceInMemory() and then adding it back to the original chart AND the clone afterwards. This doesn’t break the original chart, but I can’t tell yet if it works for the clone until I figure out the issue in Ticket LDD-704-27229. I will try to make a minimal example that causes that issue.

PS. I did upgrade to version 5.0.1.11077 just to check.

  • You must to post comments
Showing 3 results
Your Answer

Please first to submit.

Try SciChart Today

Start a trial and discover why we are the choice
of demanding developers worldwide

Start TrialCase Studies