一个自己创作的拖放框架(DragDropFramework)
在WPF编程中,拖放操作涉及的事件极多。如果每次因为有一个拖放操作需求就要监听所有事件来完成拖放操作,工作量将非常可观。为了复用代码,有人使用WPF的关联属性创作了一个拖放框架,我对其进行了完善。使用非常简单,只需要从DragSourceAdvisor和DropTargetAdvisor派生自己的类型,并重写相应的方法,并将此对象用关联属性附加到支持拖放的元素中,那么就可以支持拖放操作了,如下:
<Window x:Class="DragDropFramework.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:***"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<local:ToolBoxDragSourceAdvisor x:Key="dragAdvisor"/>
<local:ToolBoxDropTargetAdvisor x:Key="tbDropAdvisor"/>
<local:DrawingSurfaceDropTargetAdvisor x:Key="dropAdvisor"/>
</Window.Resources>
<Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Canvas local:DragDropManager.DragSourceAdviser="{StaticResource dragAdvisor}" Background="LightCyan"
local:DragDropManager.DropTargetAdviser="{StaticResource tbDropAdvisor}" >
<Rectangle Name="r" Fill="Red" Width="100" Height="60" Stroke="Green" StrokeThickness="3" RadiusX="10" RadiusY="10"/>
</Canvas>
<Canvas Background="LightCoral" Grid.Column="1" local:DragDropManager.DropTargetAdviser="{StaticResource dropAdvisor}"/>
</Grid>
</Grid>
</Window>
至于原理,不再详述了,直接贴代码。代码中有详细的注释。
核心类:DragDropManager,DragSourceAdvisor,DragTargetAdvisor,DragDropManager将在拖放操作的不同阶段调用后两者的方法。后两者是抽象类,必须从其派生来获得想要的拖放效果。
public static class DragDropManager
{
#region DragSourceAdviser Attached Property Definition
public static DragSourceAdvisor GetDragSourceAdviser(DependencyObject obj)
{
return (DragSourceAdvisor)obj.GetValue(DragSourceAdviserProperty);
}
public static void SetDragSourceAdviser(DependencyObject obj, DragSourceAdvisor value)
{
obj.SetValue(DragSourceAdviserProperty, value);
}
public static readonly DependencyProperty DragSourceAdviserProperty = DependencyProperty.RegisterAttached(
"DragSourceAdviser",
typeof(DragSourceAdvisor),
typeof(DragDropManager),
new FrameworkPropertyMetadata(OnDragSourceAdvisorChanged));
private static void OnDragSourceAdvisorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
UIElement source = sender as UIElement;
if (e.NewValue != null)
{
source.PreviewMouseLeftButtonDown += SourcePreviewMouseLeftButtonDown;
source.PreviewMouseMove += SourcePreviewMouseMove;
source.PreviewMouseUp += SourcePreviewMouseUp;
source.PreviewGiveFeedback += SourcePreviewGiveFeedback;
source.PreviewQueryContinueDrag += SourcePreviewQueryContinueDrag;
DragSourceAdvisor advisor = e.NewValue as DragSourceAdvisor;
advisor.Source = source;
}
if (e.OldValue != null)
{
source.PreviewMouseLeftButtonDown -= SourcePreviewMouseLeftButtonDown;
source.PreviewMouseMove -= SourcePreviewMouseMove;
source.PreviewMouseUp -= SourcePreviewMouseUp;
source.GiveFeedback -= SourcePreviewGiveFeedback;
}
}
#endregion
#region DropTargetAdviser Attached Property Definition
public static DropTargetAdvisor GetDropTargetAdviser(DependencyObject obj)
{
return (DropTargetAdvisor)obj.GetValue(DropTargetAdviserProperty);
}
public static void SetDropTargetAdviser(DependencyObject obj, DropTargetAdvisor value)
{
obj.SetValue(DropTargetAdviserProperty, value);
}
public static readonly DependencyProperty DropTargetAdviserProperty = DependencyProperty.RegisterAttached(
"DropTargetAdviser",
typeof(DropTargetAdvisor),
typeof(DragDropManager),
new FrameworkPropertyMetadata(OnDropTargetAdvisorChanged));
private static void OnDropTargetAdvisorChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
{
UIElement target = sender as UIElement;
if (e.NewValue != null)
{
target.PreviewDragEnter += TargetPreviewDragEnter;
target.PreviewDragOver += TargetPreviewDragOver;
target.PreviewDragLeave += TargetPreviewDragLeave;
target.PreviewDrop += Target