Sous Windows 8; Je souhaite transmettre le contenu d'un MemoryStream à une classe qui accepte un paramètre de type Windows.Storage.Streams.IRandomAccessStream. Est-il possible de convertir ce MemoryStream en un IRandomAccessStream?
Réponses
Trop de publicités?Dans Windows8, .NET et WinRT types sont généralement converties ou de types compatibles sous le capot de sorte que vous n'avez pas à s'en soucier.
Pour les cours d'eau, cependant, il existe des méthodes d'aide à convertir entre WinRT et .NET flux: Pour la conversion de WinRT flux -> .NET flux:
InMemoryRandomAccessStream win8Stream = GetData(); // Get a data stream from somewhere.
System.IO.Stream inputStream = win8Stream.AsStream()
Pour la conversion de .NET flux -> WinRT flux:
Windows.Storage.Streams.IInputStream inStream = stream.AsInputStream();
Windows.Storage.Streams.IOutputStream outStream = stream.AsOutputStream();
Mise à JOUR: 2013-09-01
Qu'il ne soit pas dit que Microsoft ne veut pas écouter de la communauté des développeurs ;)
Dans l' annonce .NET FX 4.5.1, Microsoft indique que:
Beaucoup d'entre vous ont été de vouloir un moyen de convertir un .NET diffuser à un Windows Runtime IRandomAccessStream. Appelons ça un AsRandomAccessStream méthode d'extension. Nous n'avons pas pu obtenir cette fonctionnalité dans Windows 8, mais il a été un de nos premiers ajouts à Windows 8.1 Preview.
Vous pouvez maintenant écrire le code suivant, pour télécharger une image avec HttpClient, le charger dans un BitmapImage et alors définie comme la source d'une Xaml contrôle de l'Image.
//access image via networking i/o
var imageUrl = "http://www.microsoft.com/global/en-us/news/publishingimages/logos/MSFT_logo_Web.jpg";
var client = new HttpClient();
Stream stream = await client.GetStreamAsync(imageUrl);
var memStream = new MemoryStream();
await stream.CopyToAsync(memStream);
memStream.Position = 0;
var bitmap = new BitmapImage();
bitmap.SetSource(memStream.AsRandomAccessStream());
image.Source = bitmap;
HTH.
Trouvé une solution plus élégante:
public static class MicrosoftStreamExtensions
{
public static IRandomAccessStream AsRandomAccessStream(this Stream stream)
{
return new RandomStream(stream);
}
}
class RandomStream : IRandomAccessStream
{
Stream internstream;
public RandomStream(Stream underlyingstream)
{
internstream = underlyingstream;
}
public IInputStream GetInputStreamAt(ulong position)
{
//THANKS Microsoft! This is GREATLY appreciated!
internstream.Position = (long)position;
return internstream.AsInputStream();
}
public IOutputStream GetOutputStreamAt(ulong position)
{
internstream.Position = (long)position;
return internstream.AsOutputStream();
}
public ulong Size
{
get
{
return (ulong)internstream.Length;
}
set
{
internstream.SetLength((long)value);
}
}
public bool CanRead
{
get { return this.internstream.CanRead; }
}
public bool CanWrite
{
get { return this.internstream.CanWrite; }
}
public IRandomAccessStream CloneStream()
{
throw new NotSupportedException();
}
public ulong Position
{
get { return (ulong)this.internstream.Position; }
}
public void Seek(ulong position)
{
this.internstream.Seek((long)position, SeekOrigin.Begin);
}
public void Dispose()
{
this.internstream.Dispose();
}
public Windows.Foundation.IAsyncOperationWithProgress ReadAsync(IBuffer buffer, uint count, InputStreamOptions options)
{
return this.GetInputStreamAt(this.Position).ReadAsync(buffer, count, options);
}
public Windows.Foundation.IAsyncOperation FlushAsync()
{
return this.GetOutputStreamAt(this.Position).FlushAsync();
}
public Windows.Foundation.IAsyncOperationWithProgress WriteAsync(IBuffer buffer)
{
return this.GetOutputStreamAt(this.Position).WriteAsync(buffer);
}
}
Après quelques expériences, j'ai trouvé que le code suivant fonctionnait.
using System;
using System.IO;
using System.Threading.Tasks;
using Windows.Storage.Streams;
partial class MainPage
{
public MainPage()
{
var memoryStream = new MemoryStream(new byte[] { 65, 66, 67 });
ConvertToRandomAccessStream(memoryStream, UseRandomAccessStream);
InitializeComponent();
}
void UseRandomAccessStream(IRandomAccessStream stream)
{
var size = stream.Size;
} // put breakpoint here to check size
private static async void ConvertToRandomAccessStream(MemoryStream memoryStream,
Action<IRandomAccessStream> callback)
{
var randomAccessStream = new InMemoryRandomAccessStream();
var outputStream = randomAccessStream.GetOutputStreamAt(0);
var dw = new DataWriter(outputStream);
var task = new Task(() => dw.WriteBytes(memoryStream.ToArray()));
task.Start();
await task;
await dw.StoreAsync();
var success = await outputStream.FlushAsync();
callback(randomAccessStream);
}
}
UPDATE: J'ai également essayé une méthode plus élégante:
private static void ConvertToRandomAccessStream(MemoryStream memoryStream,
Action<IRandomAccessStream> callback)
{
var randomAccessStream = new InMemoryRandomAccessStream();
var outputStream = randomAccessStream.GetOutputStreamAt(0);
RandomAccessStream.Copy(memoryStream.AsInputStream(), outputStream);
callback(randomAccessStream);
}
Étrangement, ça ne marche pas. Quand j'appelle stream.Size
plus tard, je reçois zéro.
UPDATE J'ai changé la fonction pour retourner le IRandomAccessStream plutôt que d'utiliser la fonction de rappel
public static async Task<IRandomAccessStream> ConvertToRandomAccessStream(MemoryStream memoryStream)
{
var randomAccessStream = new InMemoryRandomAccessStream();
var outputStream = randomAccessStream.GetOutputStreamAt(0);
var dw = new DataWriter(outputStream);
var task = new Task(() => dw.WriteBytes(memoryStream.ToArray()));
task.Start();
await task;
await dw.StoreAsync();
await outputStream.FlushAsync();
return randomAccessStream;
}
Aucune de ces solutions ne fonctionne pour moi aujourd'hui (peut-être quelques modifications de l'API depuis la publication des réponses). La seule façon qui fonctionne est
IRandomAccessStream inMemoryStream = new InMemoryRandomAccessStream();
using (var inputStream = stream.AsInputStream())
{
await RandomAccessStream.CopyAsync(inputStream, inMemoryStream);
}
inMemoryStream.Seek(0);