Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

[How to] Listen to your DragEventArgs!

0.00/5 (No votes)
12 Apr 2017 1  
How to wire up drag+drop events through multiple objects.

The Problem

Handling just about anything in code-behind is bad (generally speaking) and can very easily create tightly coupled dependencies.  Handling events, like drag+drop, in code-behind makes it even easier to produce these dependencies.

So how do you handle drop events if it's not in the code-behind?

The Solution (sample code)

Quick FYI - I just figured this out and wanted to share!  There are most likely better ways to handle or go about solving this, so let me know in the comments if you know any.

 

I find examples to be the best way for me to explain a concept.  Let's say you have a UserControl, we'll call it MyView, that has the initial drop event defined.  We also have the main window class (MainWindow) that will have MyView as a child element .  In this example the MainWindow will listen to the Drop event of MyView and subsequently call a method of it's ViewModel (MainWindowViewModel) to handle the logic.

Keep in mind that the point of this tip/trick is only to show how to enable listening to an event that uses DragEventArgs (like Drop or DragEnter).  Where you actually listen from is up to you.

UserControl MyView:

MyView.xaml
<UserControl x:Class="MyProject.Views.MyView"

             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 

             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 

             mc:Ignorable="d" 

             d:DesignHeight="300" d:DesignWidth="300"

             x:Name="uc_View">
    <Grid>
        <ListBox Name="lbxView" AllowDrop="True" Drop="lbxView_Drop">
            <!-- Add listbox content here -->
        </ListBox>
    </Grid>
</UserControl>

Key code:

AllowDrop basically enables the drag/drop.

Drop is where we give the method name that will be called on a drop event.

 

MyView.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;

namespace MyProject.Views
{
    /// <summary>
    /// Interaction logic for MyView.xaml
    /// </summary>
    public partial class MyView : UserControl
    {
        // Define an 'EventHandler' for an object to listen to.
        // The name doesn't really matter, just know that this is what other
        // objects will reference when adding their listener.
        public event EventHandler<DragEventArgs> ObjectDropped;
        
        // Define how to invoke/call this event
        protected virtual void OnObjectDropped(DragEventArgs e)
        {
            ObjectDropped?.Invoke(this, e);
        }
        
        // Define the drop method that we specified in the MyView.xaml file
        private void lbxView_Drop(object sender, DragEventArgs e)
        {
            OnObjectDropped(sender, e);
        }
    }
}

Key code:

EventHandler<> we need to use the template version of the EventHandler in order for this to work.  This is also the public handle for other objects to add their listening method.

lbxView_Drop is fired on the drop event and essentially calls the listening delegates.

 

Window MainWindow:

MainWindow.xaml
<Window x:Class="MyProject.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

        xmlns:local="clr-namespace:MyProject"

        xmlns:localViews="clr-namespace:MyProject.Views"

        Title="MyApp" Height="500" Width="720">
    <Grid>
        <localViews:MyView x:Name="myView" ObjectDropped="MyView_ObjectDropped"/>
    </Grid>
</Window>

Key code:

ObjectDropped is that public event handle I mentioned earlier.  This is where you pass in the listening method name.

MainWindow.xaml.cs
using System.Windows;
using MyProject.ViewModels;

namespace MyProject
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        // Just for a simple demonstration of passing the logic to the ViewModel
        private MainWindowViewModel _viewModel;
        
        private void MyView_ObjectDropped(object sender, DragEventArgs e)
        {
            // Handle the drop logic here!
            // Example:
            _viewModel.ObjectDropped( sender, e );
        }
    }
}

There's not really any key code here and is mainly here for completeness.  Yes, the handling of the ViewModel could be abstracted away, but that's out of the scope of this article.


Window MainWindow (alternate):

I strongly advise against this, but I know that what follows may be the best option for someone else.

The other way you can add the listener is to omit the ObjectDropped="MyView_ObjectDropped" in MainWindow.xaml and add the listener from the MainWindow's constructor.

MainWindow.xaml.cs (alternate)
using System.Windows;

namespace MyProject
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            myView.ObjectDropped += new EventHandler<DragEventArgs>(MyView_ObjectDropped);
        }
            
        private void MyView_ObjectDropped(object sender, DragEventArgs e)
        {
            // Handle the drop logic here!
        }
    }
}

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here