How to drag WritableBitmap between Image Controls?

帕菲菲 141 Reputation points
2020-04-19T06:14:15.837+00:00

Context:
Image1 is a Windows.UI.Xaml.Controls.Image
Image1.Source is WritableBitmap1, which is a Windows.UI.Xaml.Media.Imaging.WritableBitmap
Image2 is a Windows.UI.Xaml.Controls.Image
Now I want to drag Image1 to Image2, so that they show the same image. Now the code works like this:
When Image1.DragStarting:

args.Data.SetBitmap(RandomAccessStreamReference.CreateFromStream(WritableBitmap1.PixelBuffer.AsStream.AsRandomAccessStream))

When Image2.Drop (e As DragEventArgs):

Await (Await e.DataView.GetBitmapAsync()).OpenReadAsync'←Exception occurs here

The IRandomAccessStreamReference.OpenReadAsync() function fails:
System.NotSupportedException:“This IRandomAccessStream does not support the CloneStream method because it requires cloning and this stream does not support cloning.”

WritableImage1 is created programmatically and thus no files can be used as a source.

Universal Windows Platform (UWP)
0 comments No comments
{count} votes

Accepted answer
  1. Fay Wang - MSFT 5,196 Reputation points
    2020-04-20T05:03:24.453+00:00

    Hello,

    Welcome to Microsoft Q&A!

    This IRandomAccessStream does not support the CloneStream method because it requires cloning and this stream does not support cloning.

    This exception is because the parameter CreateFromStream method of RandomAccessStreamReference needs is Windows.Storage.Streams.IRandomAccessStream, but the type of WritableBitmap1.PixelBuffer.AsStream.AsRandomAccessStream is System.IO.IRandomAccessStream. So you need to convert the WritableBitmap to Windows.Storage.Streams.IRandomAccessStream. For example:

    IRandomAccessStream randomStream = new InMemoryRandomAccessStream();
    DataWriter dataWriter = new DataWriter(randomStream);
    dataWriter.WriteBuffer(WritableBitmap1.PixelBuffer, 0, WritableBitmap1.PixelBuffer.Length);
    await dataWriter.StoreAsync();
    
     args.Data.SetBitmap(RandomAccessStreamReference.CreateFromStream(randomStream));
    

2 additional answers

Sort by: Most helpful
  1. John Torjo 861 Reputation points
    2020-04-20T07:15:04.767+00:00

    I haven't tested it, but I have played a bit with drag and drop.

    You can, if you want, to do the drag-and-drop differently. Namely, put the bitmap in e.Data.Properties, like e.Data.Properties.Add("bitmap", your_bitmap)

    On drop, you'll use e.DataView.Properties["bitmap"] as WriteableBitmap, and you should be fine.

    As far as I know, you can have several image controls have the same source.


  2. 帕菲菲 141 Reputation points
    2020-04-21T06:10:31.213+00:00

    Here comes my final solution.

    1. Create a new InMemoryRandomAccessStream and a BitmapEncoder: Dim j As New InMemoryRandomAccessStream, d As BitmapEncoder = Await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, j)
    2. Call SoftwareBitmap.CreateCopyFromBuffer to get a SoftwareBitmap from the PixelBuffer of the WritableBitmap, and set it to the BitmapEncoder.SetSoftwareBitmap, then FlushAsync.
    3. RandomAccessStreamReference.CreateFromStream(j) and pass it to the DataPackage.SetBitmap.
    4. Now the receiver gets the DataPackageView, GetBitmapAsync and then OpenReadAsync
    5. Create a BitmapDecoder by BitmapDecoder.CreateAsync, and GetSoftwareBitmapAsync.

    I've tried that this even works for other apps that get the DataPackageView from Clipboard.

    0 comments No comments