[How to] Listen to your DragEventArgs!





1.00/5 (1 vote)
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!
}
}
}