Search code examples
c#imageuwpxmldocument

How can I set the SvgImageSource property of an Image component from the contents of an XmlDocument in a UWP app?


I have a Windows 10 UWP application – using Prism MVVM – in which I programmatically – in C# – create some SVG XML in an XmlDocument which I need to display in an existing Image component.

In my XAML I have:

<Image
 Source="{x:Bind ViewModel.SvgSource, Mode=OneWay}"
 Stretch="Uniform" />

In my ViewModel I have:

private SvgImageSource _svgSource;
public SvgImageSource SvgSource
{
 get => _svgSource;
 set => _ = SetProperty(ref _svgSource, value);
}

...and I set the source in the View Model via:

private SVGGenerator generator;
SvgSource = await generator.GetSourceAsync(_generationCancellationTokenSource.Token);

While in my SVGGenerator class I have (amongst other methods):

public async Task<IRandomAccessStream> GetSourceAsync(CancellationToken cancellationToken)
{
 return await Task.Run(() =>
   {
     using (var stringWriter = new StringWriter())
     {
       XmlWriterSettings settings = new XmlWriterSettings
       {
         Indent = true,
         Encoding = Encoding.UTF8
       };
       using (var memoryStream = new MemoryStream())
       {
         using (var xmlTextWriter = XmlWriter.Create(memoryStream, settings))
         {
           _document.WriteTo(xmlTextWriter);
           xmlTextWriter.Flush();
           var ramStream = new InMemoryRandomAccessStream();
           memoryStream.CopyTo(ramStream);
           ramStream.Seek(0);
           return ramStream;
         }
       }
     }
   }, cancellationToken
 );
}

The memoryStream.CopyTo(ramStream); line does not compile - CS1503 C# Argument 1: cannot convert from ‘Windows.Storage.Streams.InMemoryRandomAccessStream’ to 'System.IO.Stream' - because MemoryStream can’t write to an InMemoryRandomAccessStream (or, to put it another way, I can’t figure out how to do it).

Some texts – e.g. How to convert byte array to InMemoryRandomAccessStream or IRandomAccessStream in windows 8 – I have seen suggest using memoryStream.AsRandomAccessStream() but I can’t figure out how to use the .AsRandomAccessStream() extension method (it’s not available to me and I don’t know where to get it as the code available doesn’t show the using statements).

Other texts – e.g. https://csharp.hotexamples.com/examples/Windows.Storage.Streams/InMemoryRandomAccessStream/AsStream/php-inmemoryrandomaccessstream-asstream-method-examples.html – suggest using memoryStream.CopyTo(ramStream.AsStream()); but the .AsStream() extension isn’t available for similar reasons.

I’m going round and round in circles at the moment.

'All' I want to do is either write the text from an XmlDocument directly to an InMemoryRandomAccessStream or copy the contents of a MemoryStream to an InMemoryRandomAccessStream but I just can’t figure out how to do either.

Can anyone help me please? Should I be doing this in another (simpler) way?


Solution

  • For testing your code, I found memoryStream parameter is output type, but you send empty MemoryStream to the method. So, please try to modify WriteTo to Save method that could make sure memoryStream has content. I post the complete GetSourceAsync below, and you could use it directly.

    public async Task<IRandomAccessStream> GetSourceAsync(CancellationToken cancellationToken)
    {
        return await Task.Run(async () =>
        {
            using (var stringWriter = new StringWriter())
            {
                XmlWriterSettings settings = new XmlWriterSettings
                {
                    Indent = true,
                    Encoding = Encoding.UTF8
                };
                using (var memoryStream = new MemoryStream())
                {
                    using (var xmlTextWriter = XmlWriter.Create(memoryStream, settings))
                    {
                        _document.Save(xmlTextWriter);
                        xmlTextWriter.Flush();
                        var ibuffer = memoryStream.GetWindowsRuntimeBuffer();
                        InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
                        await randomAccessStream.WriteAsync(ibuffer);
                        randomAccessStream.Seek(0);
                        return randomAccessStream;
                    }
                }
            }
        }, cancellationToken
        );
    }