WPF中的拖放操作及其解决方案

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]); } } } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485