¿Hay alguna forma de convertir un System.IO.Stream a Windows.Storage.Streams.IRandomAccessStream?

En Windows 8; Me gustaría pasar el contenido de un MemoryStream a una clase que acepte un parámetro de tipo Windows.Storage.Streams.IRandomAccessStream. ¿Hay alguna forma de convertir este MemoryStream a un IRandomAccessStream?

Para usar las extensiones: debe agregar “using System.IO”

En Windows8, los tipos .NET y WinRT generalmente se convierten a / desde tipos compatibles bajo el capó, por lo que no tiene por qué preocuparse.

Sin embargo, para las transmisiones, existen métodos de ayuda para convertir entre las secuencias WinRT y .NET: para la conversión de las transmisiones WinRT -> las transmisiones .NET:

InMemoryRandomAccessStream win8Stream = GetData(); // Get a data stream from somewhere. System.IO.Stream inputStream = win8Stream.AsStream() 

Para convertir secuencias .NET -> secuencias WinRT:

 Windows.Storage.Streams.IInputStream inStream = stream.AsInputStream(); Windows.Storage.Streams.IOutputStream outStream = stream.AsOutputStream(); 

ACTUALIZACIÓN: 2013-09-01

Que no se diga que Microsoft no escucha su comunidad de desarrolladores;)

En el anuncio de .NET FX 4.5.1 , Microsoft declara que:

Muchos de ustedes han estado buscando una manera de convertir un .NET Stream a un Windows Runtime IRandomAccessStream. Vamos a llamarlo un método de extensión AsRandomAccessStream. No pudimos obtener esta característica en Windows 8, pero fue una de nuestras primeras incorporaciones a la Vista previa de Windows 8.1.

Ahora puede escribir el siguiente código, descargar una imagen con HttpClient, cargarla en una BitmapImage y luego configurarla como fuente para un control de imagen Xaml.

  //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.

Encontré una solución más elegante:

 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); } } 

Después de experimentar un poco, encontré que el siguiente código funcionaba.

 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 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); } } 

ACTUALIZACIÓN: también probé la implementación de métodos más elegantes:

  private static void ConvertToRandomAccessStream(MemoryStream memoryStream, Action callback) { var randomAccessStream = new InMemoryRandomAccessStream(); var outputStream = randomAccessStream.GetOutputStreamAt(0); RandomAccessStream.Copy(memoryStream.AsInputStream(), outputStream); callback(randomAccessStream); } 

Extrañamente, no funciona. Cuando llamo a stream.Size más tarde, obtengo cero.

ACTUALIZAR Cambié la función para devolver IRandomAccessStream en lugar de usar la función de callback

 public static async Task 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; } 

No hay un método incorporado en Windows 8. Para Windows 8.1, agregamos un método de extensión Stream.AsRandomAccessStream ():

 internal static IRandomAccessStream ToRandomAccessStream(byte[] array) { MemoryStream stream = new MemoryStream(array); return stream.AsRandomAccessStream(); } 

Ninguno de los anteriores funciona para mí hoy (tal vez algunos cambios de API desde que se publicaron las respuestas). La única forma en que funciona es

 IRandomAccessStream inMemoryStream = new InMemoryRandomAccessStream(); using (var inputStream = stream.AsInputStream()) { await RandomAccessStream.CopyAsync(inputStream, inMemoryStream); } inMemoryStream.Seek(0); 

Este fragmento de código convierte una secuencia ( stream ) en InMemoryRandomAccessStream ( ims ) que implementa IRandomAccessStream . El truco es que se debe invocar CopyTo en un hilo de fondo.

  InMemoryRandomAccessStream ims = new InMemoryRandomAccessStream(); var imsWriter = ims.OpenWrite(); await Task.Factory.StartNew(() => stream.CopyTo(imsWriter)); 

Eche un vistazo a este enlace:

Cómo convertir una matriz de bytes a IRandomAccessStream

También proporciona ejemplos y una implementación de un constructor de matriz de bytes (y uno para las secuencias de .NET), útil si desea utilizar los métodos SetSource o SetSourceAsync de la clase BitmapImage (como en mi caso).

Espero que esto ayude a alguien…