在WPF(Windows Presentation Foundation)中实现拖放操作时,可能会遇到一些挑战。例如,尝试将一个项目拖放到TextBox控件中时,会发现鼠标光标显示为“拒绝放置”的光标,并且无法将项目放置到该字段中。这种现象同样适用于RichTextBox和FlowDocument控件。即使将AllowDrop属性设置为true,这些特定的控件也会将拖放事件标记为已处理,从而阻止自己处理这些事件。
这看起来可能是一个很大的问题,似乎表明无法将内容拖放到TextBox中,这似乎是微软的一个重大疏忽。幸运的是,通过了解WPF如何处理命令,可以很容易地找到一个变通方法。记住说过WPF将这些操作标记为已处理吗?这是能够绕过它的关键——每个特定的事件(例如DragOver事件)都有一个对应的Preview事件,可以钩住它来执行处理。
在展示代码之前,原始帖子(OP)提出了一个后续问题:“关于解决方案,有一个具体的问题,那就是当拖放操作进入编辑框时,会得到一个带有加号的标准鼠标光标。在最初解决ListBox拖放问题的解决方案中,得到的是一个带有空盒子的鼠标光标,而不是带有加号的盒子。通过实验,发现可以通过PreviewDrag事件中的代码实现这一点。那么,是什么代码让得到了带有加号的光标,避免了没有加号的贫血光标呢?”
以下文件拖放示例展示了如何通过改变DragDropEffects参数来改变放置光标的显示,以回答原始帖子的后续问题:
<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>
仔细观察代码,可以看到PreviewDragEnter和PreviewDragOver绑定到同一个事件处理程序。PreviewDrop事件映射到一个不同的事件处理程序,实际上在其中执行文件名的放置。
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
{
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]);
}
}
}
}