UWP DropImageBehavior - drag and drop photos using a behavior

UWP DropImageBehavior - drag and drop photos using a behavior

I wrote a simple but useful UWP behavior that's based on the great XAML Behaviors SDK and allows easy, reusable way to add drag and drop support for photos. The idea is to just be able to define the behavior on the drop surface and set the target image object.

Dragging and dropping images usually takes some code behind unless behaviors are used so it can be plugged in anywhere in XAML declaratively.

Here's the code for the behavior:

[ContentProperty(Name = "Actions")]
public class DropImageBehavior : DependencyObject, IBehavior  
{
    private BitmapImage bitmapImage = null;

    public static readonly DependencyProperty ActionsProperty = DependencyProperty.Register(nameof(Actions), typeof(ActionCollection), typeof(DropImageBehavior), new PropertyMetadata(null));
    public static readonly DependencyProperty TargetImageProperty = DependencyProperty.Register(nameof(TargetImage), typeof(Image), typeof(DropImageBehavior), new PropertyMetadata(null));

    public ActionCollection Actions
    {
        get
        {
            ActionCollection actionCollection = this.GetValue(ActionsProperty) as ActionCollection;

            if (actionCollection == null)
            {
                actionCollection = new ActionCollection();

                this.SetValue(DropImageBehavior.ActionsProperty, actionCollection);
            }

            return actionCollection;
        }
    }

    public DependencyObject AssociatedObject { get; private set; }

    public Image TargetImage
    {
        get { return GetValue(TargetImageProperty) as Image; }
        set { SetValue(TargetImageProperty, value); }
    }

    public void Attach(DependencyObject associatedObject)
    {
        if (this.AssociatedObject != associatedObject)
        {
            this.AssociatedObject = associatedObject;

            var frameworkElement = associatedObject as FrameworkElement;

            if (frameworkElement != null)
            {
                frameworkElement.AllowDrop = true;
                frameworkElement.DragOver += FrameworkElement_DragOver;
                frameworkElement.Drop += FrameworkElement_Drop;
            }
        }
    }

    public void Detach()
    {
        var frameworkElement = this.AssociatedObject as FrameworkElement;

        if (frameworkElement != null)
        {
            frameworkElement.AllowDrop = false;
            frameworkElement.DragOver -= FrameworkElement_DragOver;
            frameworkElement.Drop -= FrameworkElement_Drop;
        }

        this.bitmapImage = null;
        this.TargetImage = null;
    }

    private void FrameworkElement_DragOver(object sender, DragEventArgs e)
    {
        e.AcceptedOperation = DataPackageOperation.Copy;
    }

    private async void FrameworkElement_Drop(object sender, DragEventArgs e)
    {
        if (e.DataView.Contains(StandardDataFormats.StorageItems))
        {
            var items = await e.DataView.GetStorageItemsAsync();
            var storageFile = items.FirstOrDefault() as StorageFile;

            if ((storageFile != null) && (storageFile.ContentType == "image/jpeg") && (this.TargetImage != null))
            {
                this.bitmapImage = new BitmapImage();

                using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read))
                {
                    await bitmapImage.SetSourceAsync(stream);
                }

                this.TargetImage.Source = bitmapImage;
                Interaction.ExecuteActions(this.AssociatedObject, this.Actions, null);
            }
        }
    }
}

Using it is really straightforward. Just have a TargetImage somewhere in XAML:

<Image x:Name="TargetImage" />  

define the drop surface, add the behavior and connect it with the target image.

<Border x:Name="DropSurface"  
        Width="320"
        Height="240"
        Background="Green" 
        HorizontalAlignment="Right"
        VerticalAlignment="Top">
    <interactivity:Interaction.Behaviors>
        <local:DropImageBehavior TargetImage="{x:Bind TargetImage}" />
    </interactivity:Interaction.Behaviors>
</Border>  

UWP drop photo on a surface

Conclusion

XAML behaviors are super useful for defining reusable interactivity components that can be used declaratively, straight in XAML.

What behaviors are your favourite ones? Leave a comment!

Igor Ralic

igor ralic

View Comments
Microsoft Certified Solutions Developer: Windows Store Apps in C#