Click here to Skip to main content
15,867,330 members
Articles / Desktop Programming / WPF

Textbox Drag/Drop in WPF

Rate me:
Please Sign up or sign in to vote.
5.00/5 (13 votes)
28 Sep 2009CPOL2 min read 82.7K   13   12
Textbox Drag/Drop in WPF

So last week, somebody posted a question on CodeProject about why a Drag Drop into a TextBox in WPF doesn't actually work. When you attempt to drag and drop an item into a TextBox, it refuses to cooperate and leaves the mouse cursor as the Drop denied cursor and you can't drop into the field. (Incidentally, this behaviour also applies to RichTextBox and FlowDocument controls). The reason that you can't drop into these fields, even if you set AllowDrop to true, is that these particular controls mark drag and drop events as handled, preventing you from handling them yourself.

Now this might seem like a big problem – it certainly makes it look like you can't drag/drop into a textbox, and this would seem to be a huge oversight on Microsoft’s part. Fortunately, with a little bit of knowledge of how WPF handles commands, it’s actually fairly easy to come up with a workaround. Remember that I said that WPF marks these operations as handled? This is the key to being able to work around it – each particular event (such as a DragOver event), also has a corresponding Preview event which we can hook into to perform our processing. Before I show you the code though, the OP posted a follow up query:

“A specific question I have about your solution is that you get the standard mouse cursor with the plus sign inside a box when the drag operation enters the edit box. In my initial solution to the drop into a ListBox, I got a mouse cursor with an empty box, not the box with the plus sign. By experimenting, I determined that you achieve this with the code you have in the PreviewDrag events. What about that code gets you the cursor with the plus sign, avoiding that anemic cursor without the plus sign?”

The following filename drag/drop sample demonstrates how changing the DragDropEffects parameter changes the appearance of the drop cursor, in answer to the Original Posters followup question:

XML
<Window x:Class="SampleDragDrop.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  Title="Window1" Height="274" Width="300">
  <Window.Resources>
    <ObjectDataProvider
        MethodName="GetValues"
        ObjectType="{x:Type sys:Enum}"
        x:Key="DragProvider">
      <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="DragDropEffects" />
      </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="Margin" Value="3" />
      <Setter Property="VerticalAlignment" Value="Center" />
    </Style>
  </Window.Resources>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="101*" />
      <ColumnDefinition Width="177*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="27*" />
      <RowDefinition Height="203.258*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock Text="Drag Drop Effects" Grid.Column="0" Grid.Row="0" />
    <TextBlock Text="Drop target" Grid.Column="0" Grid.Row="1" />
    <TextBlock Text="Handled" Grid.Column="0" Grid.Row="2" />
    <ComboBox
      x:Name="cboDropEffects"
      Grid.Row="0"
      Grid.Column="1"
      Margin="2"
      SelectedIndex="0"
      ItemsSource="{Binding Source={StaticResource DragProvider}}" />
    <TextBox
      Grid.Row="1"
      Grid.Column="1"
      Margin="2"
      PreviewDragEnter="TextBox_PreviewDragEnter"
      PreviewDragOver="TextBox_PreviewDragEnter"
      PreviewDrop="TextBox_PreviewDrop" />
    <CheckBox x:Name="chkHandled" IsChecked="True" Grid.Row="2" 
	Grid.Column="1" Margin="2" />
  </Grid>
</Window>

If you look carefully at the code, you see that we bind PreviewDragEnter and the PreviewDragOver to the same event handler. The PreviewDrop event maps to a different event handler, where we actually perform the drop of the filename.

C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SampleDragDrop
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    public Window1()
    {
      InitializeComponent();
    }

    private void TextBox_PreviewDragEnter(object sender, DragEventArgs e)
    {
      e.Effects = (DragDropEffects)cboDropEffects.SelectedItem;
      if (chkHandled.IsChecked.HasValue)
      {
        e.Handled = chkHandled.IsChecked.Value;
      }
    }

    private void TextBox_PreviewDrop(object sender, DragEventArgs e)
    {
      object text = e.Data.GetData(DataFormats.FileDrop);
      TextBox tb = sender as TextBox;
      if (tb != null)
      {
        tb.Text = string.Format("{0}", ((string[])text)[0]);
      }
    }
  }
}

When you run the sample, play around with the Drag Drop Effects values, and setting/unsetting the Handled checkbox, to see what behaviour the textbox exhibits (and the answer to the OPs question, is that setting e.Effects to DragDropEffects.All sets the cursor to the relevant cursor).

This sample is available at SampleDragDrop. Don't forget to change the extension from .doc to .zip when you download it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
CEO
United Kingdom United Kingdom
A developer for over 30 years, I've been lucky enough to write articles and applications for Code Project as well as the Intel Ultimate Coder - Going Perceptual challenge. I live in the North East of England with 2 wonderful daughters and a wonderful wife.

I am not the Stig, but I do wish I had Lotus Tuned Suspension.

Comments and Discussions

 
GeneralMy vote of 5 Pin
WESTSEYI12-Aug-13 11:16
WESTSEYI12-Aug-13 11:16 
QuestionI am boggled!! Pin
Member 78033551-Jan-13 22:50
Member 78033551-Jan-13 22:50 
GeneralMy vote of 5 Pin
Gjeltema29-Aug-12 18:04
Gjeltema29-Aug-12 18:04 
GeneralMy vote of 5 Pin
Member 889799928-May-12 22:25
Member 889799928-May-12 22:25 
GeneralMy vote of 5 Pin
dmcmullan7-Jul-10 10:15
dmcmullan7-Jul-10 10:15 
GeneralVery Helpful Pin
StewBob10-Jun-10 9:01
StewBob10-Jun-10 9:01 
Thanks Pete, your bit of code handling the PreviewDrop was very helpful. I am working on data validation for textboxes, and don't want anyone dropping text data into my numeric boxes. The e.Data.GetData(DataFormats.xxxx) was the tricky bit I needed.

Thanks again.

There are two kinds of people. Those who need closure

GeneralNull Reference Pin
George Swan28-Sep-09 21:41
mveGeorge Swan28-Sep-09 21:41 
GeneralRe: Null Reference Pin
Pete O'Hanlon29-Sep-09 8:41
subeditorPete O'Hanlon29-Sep-09 8:41 
GeneralRe: Null Reference Pin
George Swan29-Sep-09 21:10
mveGeorge Swan29-Sep-09 21:10 
GeneralRe: Null Reference Pin
Pete O'Hanlon30-Sep-09 1:51
subeditorPete O'Hanlon30-Sep-09 1:51 
GeneralPreview Events Pin
AspDotNetDev28-Sep-09 12:12
protectorAspDotNetDev28-Sep-09 12:12 
GeneralRe: Preview Events Pin
Pete O'Hanlon28-Sep-09 12:18
subeditorPete O'Hanlon28-Sep-09 12:18 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.