Reading the title, you are probably even wondering why this even
deserves a tutorial. Disabling the ability to drag selected text out of
a
TextBox
? That has got to just be a flag somewhere, right? That is
what I thought, and it turns out I was quite wrong.
The
TextBox
in WPF has a lot of built in behavior, from responding to
keyboard shortcuts for copy/paste to having its own context menu. It
even has a built in spell checker and undo stack! One of these built in
features is the ability to drag selected text into and out of a
TextBox
. Generally, this is probably a nice feature to have (although
I don't ever use it) - but sometimes it can get in the way. For
instance, if your application is paying close attention to mouse capture
or focus (say you are inside a popup), an errant drag operation started
from within your captured area doesn't generally do useful things.
Disabling dropping into a
TextBox
is pretty easy - all you have to do
is set the
AllowDrop
property on the TextBox
to false. Disabling dragging, on the other
hand, is not so easy. None of the properties on TextBlock
seemed to be
relevant, and when I tried to Google for the answer, the best that I
found was forumpost
on MSDN. And guess what - the forum post said that what I was trying to
do was impossible!
Well, that annoyed me to no end, so I broke out Reflector and started
working my way backward through the framework code. I'll spare you the
horrifying gritty details of my search - suffice it to say, I was
successful in my quest! You can in fact disable dragging from a
TextBox
, and it is actually pretty simple to do. So simple, in fact,
that I'm just going to drop all the code for it in one block:
<Window x:Class="WpfTextBoxDragCopy.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="DataObject Event Test" Height="138" Width="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Text="Regular TextBox: " Grid.Row="0" Grid.Column="0" />
<TextBox x:Name="_TextBlock1" Grid.Row="0" Grid.Column="1" />
<TextBlock Text="No Copy: " Grid.Row="1" Grid.Column="0" />
<TextBox x:Name="_TextBlock2" Grid.Row="1" Grid.Column="1" />
<TextBlock Text="No Drag Copy: " Grid.Row="2" Grid.Column="0" />
<TextBox x:Name="_TextBlock3" Grid.Row="2" Grid.Column="1" />
<TextBlock Text="No Paste: " Grid.Row="3" Grid.Column="0" />
<TextBox x:Name="_TextBlock4" Grid.Row="3" Grid.Column="1" />
</Grid>
</Window>
using System.Windows;
namespace WpfTextBoxDragCopy
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataObject.AddCopyingHandler(_TextBlock2, NoCopy);
DataObject.AddCopyingHandler(_TextBlock3, NoDragCopy);
DataObject.AddPastingHandler(_TextBlock4, NoPaste);
}
private void NoCopy(object sender, DataObjectCopyingEventArgs e)
{
e.CancelCommand();
}
private void NoDragCopy(object sender, DataObjectCopyingEventArgs e)
{
if (e.IsDragDrop)
{ e.CancelCommand(); }
}
private void NoPaste(object sender, DataObjectPastingEventArgs e)
{
e.CancelCommand();
}
}
}
It all has to do with the events on DataObject.
When a copy (or a paste for that matter) is initiated on a
TextBox
, deep inside the TextBox
code the DataObject.Copying event is fired (or DataObject.Pasting
if it was a paste). This is a routed event, which means it bubbles up
from its source i.e., the TextBox. If anyone along the way catches the
event and calls the CancelCommand method on the event args, the copy (or paste) gets canceled.
And even better, the event args have a property called
IsDragDrop
which (you might have guessed) is true if the copy/paste was triggered
due to a drag/drop operation. So to disable dragging out of a
TextBox
,
all you have to do is listen for the DataObject.Copying
event, and if
IsDragDrop
is true, call CancelCommand
.
For the example above, that particular sequence of events happens for
_TextBox3
. _TextBox2
shows disabling copying altogether, and
_TextBox4
shows disabling pasting altogether.
As a random side note, if you use a
PasswordBox
(a special form of
TextBox
) copying anything out through any of the
standard means (drag, keyboard shortcut, context menu) is completely
disabled. In fact, while browsing the code in Reflector, I found that it
is hard coded to be disabled (which makes sense - being able to copy a
password out of a password box is kind of a security risk).
That is it for this short snippet - I hope it has saved you some time. I
know that if I had found a post like this when I was looking, it would
have saved an annoying hour in Reflector. As always, you can grab the
source for the example below.
Source Files:
Comments
Post a Comment