WPF 4以可视元素作为光标进行拖放
我有一个WPF 4应用程序,我想启用拖放功能,目前我有一个基本的拖放实现,但我发现如果我可以在手指下使用一个图像,而不是鼠标光标切换来表示移动操作,那会更好WPF 4以可视元素作为光标进行拖放,wpf,drag-and-drop,.net-4.0,Wpf,Drag And Drop,.net 4.0,我有一个WPF 4应用程序,我想启用拖放功能,目前我有一个基本的拖放实现,但我发现如果我可以在手指下使用一个图像,而不是鼠标光标切换来表示移动操作,那会更好 我的拖放操作是在自定义用户控件中启动的,因此我需要在可视化树中插入一个可视化元素,并让它跟随我的手指,也许我应该在我的主窗口上启用操纵delta事件,检查布尔值,然后移动项目?有一个使用自定义拖动光标的示例。您可以处理该事件并更改鼠标光标,但要使用自定义的视觉效果,作者会创建一个新窗口并更新其位置。从前面提到的文章中,我可以简化一点。基本上
我的拖放操作是在自定义用户控件中启动的,因此我需要在可视化树中插入一个可视化元素,并让它跟随我的手指,也许我应该在我的主窗口上启用
操纵delta
事件,检查布尔值,然后移动项目?有一个使用自定义拖动光标的示例。您可以处理该事件并更改鼠标光标,但要使用自定义的视觉效果,作者会创建一个新窗口并更新其位置。从前面提到的文章中,我可以简化一点。基本上,您需要做的是订阅3个活动:
- PreviewMouseLeftButtonDownEvent:当您按下左按钮时运行的事件,您可以通过调用
DragDrop.DoDragDrop来启动拖动操作
- DropEvent:当您丢弃某些内容时运行的事件(控件必须将
设置为AllowDrop
,才能接受丢弃)true
- GiveFeedbackEvent:始终运行的事件,允许您不断提供反馈
DragDrop.DoDragDrop(draggedItem,draggedItem.DataContext,DragDropEffects.Move)代码>第一个参数是您正在拖动的元素,第二个参数是它所携带的数据,最后是鼠标效果
此方法锁定线程。因此,调用后的所有内容都将仅在您停止拖动时执行
在drop事件中,您可以检索在DoDragDrop
调用中发送的数据
我的测试来源如下,结果如下:
全源
MainWindow.xaml
<Window x:Class="TestWpfPure.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:uc="clr-namespace:TestWpfPure"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListBox x:Name="CardListControl" AllowDrop="True" ItemsSource="{Binding Items}" />
</Grid>
</Window>
Card.xaml
<UserControl x:Class="TestWpfPure.Card"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Border x:Name="CardBorder" BorderBrush="Black" BorderThickness="3" HorizontalAlignment="Left" Height="40" VerticalAlignment="Top" Width="246" RenderTransformOrigin="0.5,0.5" CornerRadius="6">
<TextBlock Text="{Binding Text}" TextWrapping="Wrap" FontFamily="Arial" FontSize="14" />
</Border>
</Grid>
</UserControl>
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Shapes;
namespace TestWpfPure
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ObservableCollection<Card> Items { get; set; }
private readonly Style listStyle = null;
private Window _dragdropWindow = null;
public MainWindow()
{
InitializeComponent();
Items = new ObservableCollection<Card>(new List<Card>
{
new Card { Text = "Task #01" },
new Card { Text = "Task #02" },
new Card { Text = "Task #03" },
new Card { Text = "Task #04" },
new Card { Text = "Task #05" },
});
listStyle = new Style(typeof(ListBoxItem));
listStyle.Setters.Add(new Setter(ListBoxItem.AllowDropProperty, true));
listStyle.Setters.Add(new EventSetter(ListBoxItem.PreviewMouseLeftButtonDownEvent, new MouseButtonEventHandler(CardList_PreviewMouseLeftButtonDown)));
listStyle.Setters.Add(new EventSetter(ListBoxItem.DropEvent, new DragEventHandler(CardList_Drop)));
listStyle.Setters.Add(new EventSetter(ListBoxItem.GiveFeedbackEvent, new GiveFeedbackEventHandler(CardList_GiveFeedback)));
CardListControl.ItemContainerStyle = listStyle;
DataContext = this;
}
protected void CardList_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (sender is ListBoxItem)
{
var draggedItem = sender as ListBoxItem;
var card = draggedItem.DataContext as Card;
card.Effect = new DropShadowEffect
{
Color = new Color { A = 50, R = 0, G = 0, B = 0 },
Direction = 320,
ShadowDepth = 0,
Opacity = .75,
};
card.RenderTransform = new RotateTransform(2.0, 300, 200);
draggedItem.IsSelected = true;
// create the visual feedback drag and drop item
CreateDragDropWindow(card);
DragDrop.DoDragDrop(draggedItem, draggedItem.DataContext, DragDropEffects.Move);
}
}
protected void CardList_Drop(object sender, DragEventArgs e)
{
var droppedData = e.Data.GetData(typeof(Card)) as Card;
var target = (sender as ListBoxItem).DataContext as Card;
int targetIndex = CardListControl.Items.IndexOf(target);
droppedData.Effect = null;
droppedData.RenderTransform = null;
Items.Remove(droppedData);
Items.Insert(targetIndex, droppedData);
// remove the visual feedback drag and drop item
if (this._dragdropWindow != null)
{
this._dragdropWindow.Close();
this._dragdropWindow = null;
}
}
private void CardList_GiveFeedback(object sender, GiveFeedbackEventArgs e)
{
// update the position of the visual feedback item
Win32Point w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
this._dragdropWindow.Left = w32Mouse.X;
this._dragdropWindow.Top = w32Mouse.Y;
}
private void CreateDragDropWindow(Visual dragElement)
{
this._dragdropWindow = new Window();
_dragdropWindow.WindowStyle = WindowStyle.None;
_dragdropWindow.AllowsTransparency = true;
_dragdropWindow.AllowDrop = false;
_dragdropWindow.Background = null;
_dragdropWindow.IsHitTestVisible = false;
_dragdropWindow.SizeToContent = SizeToContent.WidthAndHeight;
_dragdropWindow.Topmost = true;
_dragdropWindow.ShowInTaskbar = false;
Rectangle r = new Rectangle();
r.Width = ((FrameworkElement)dragElement).ActualWidth;
r.Height = ((FrameworkElement)dragElement).ActualHeight;
r.Fill = new VisualBrush(dragElement);
this._dragdropWindow.Content = r;
Win32Point w32Mouse = new Win32Point();
GetCursorPos(ref w32Mouse);
this._dragdropWindow.Left = w32Mouse.X;
this._dragdropWindow.Top = w32Mouse.Y;
this._dragdropWindow.Show();
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool GetCursorPos(ref Win32Point pt);
[StructLayout(LayoutKind.Sequential)]
internal struct Win32Point
{
public Int32 X;
public Int32 Y;
};
}
}
使用系统;
使用System.Collections.Generic;
使用System.Collections.ObjectModel;
使用System.Runtime.InteropServices;
使用System.Windows;
使用System.Windows.Controls;
使用System.Windows.Input;
使用System.Windows.Media;
使用System.Windows.Media.Effects;
使用System.Windows.Shapes;
命名空间TestWpfPure
{
///
///MainWindow.xaml的交互逻辑
///
公共部分类主窗口:窗口
{
公共ObservableCollection项{get;set;}
私有只读样式listStyle=null;
私有窗口_dragdropWindow=null;
公共主窗口()
{
初始化组件();
Items=新的ObservableCollection(新列表
{
新卡片{Text=“Task#01”},
新卡片{Text=“Task#02”},
新卡片{Text=“Task#03”},
新卡片{Text=“Task#04”},
新卡片{Text=“Task#05”},
});
listStyle=新样式(typeof(ListBoxItem));
添加(新的Setter(ListBoxItem.AllowDropProperty,true));
添加(新事件设置器(ListBoxItem.PreviewMouseLeftButtonDownEvent,新鼠标按钮VentHandler(CardList_PreviewMouseLeftButtonDown));
添加(新的事件设置器(ListBoxItem.DropEvent,新的DragEventHandler(CardList_-Drop));
添加(新的事件设置器(ListBoxItem.GiveFeedbackEvent,新的GiveFeedbackEventHandler(CardList_GiveFeedback));
CardListControl.ItemContainerStyle=listStyle;
DataContext=this;
}
受保护的无效卡片列表\u预览鼠标左键向下(对象发送器,鼠标按钮ventargs e)
{
如果(发件人是ListBoxItem)
{
var draggedItem=作为ListBoxItem的发件人;
var card=draggedItem.DataContext作为卡片;
card.Effect=新的DropShadow效果
{
颜色=新颜色{A=50,R=0,G=0,B=0},
方向=320,
阴影深度=0,
不透明度=.75,
};
card.RenderTransform=新的旋转变换(2.0300200);
draggedItem.IsSelected=true;
//创建视觉反馈拖放项
创建DragDropWindow(卡片);
DragDrop.DoDragDrop(draggedItem、draggedItem.DataContext、DragDropEffects.Move);
}
}
受保护的无效卡片列表(对象发送方、DragEventArgs e)
{
var droppedData=e.Data.GetData(卡片类型))作为卡片;
var target=(发送方作为ListBoxItem)。DataContext作为卡;
int targetIndex=CardListControl.Items.IndexOf(目标);
droppedData.Effect=null;
droppedData.RenderTransform=null;
项目。删除(删除数据);
项目。插入(targetIndex、droppedData);
//删除视觉反馈拖放项
如果(此._dragdropWindow!=null)
{
这是._dragdropWindow.Close();
此参数为.\u dragdropWindow=null;
}
}
私有作废卡片列表\u GiveFeedback(对象发送者,GiveFeedbackEventArgs e)
{
//更新视觉反馈项的位置
Win32Point w32Mouse=新的Win32Point();
GetCursorPos(参考w32Mouse);
这个._dragdropWindow.Left=w32Mouse.X;
这个._dragdropWindow.Top=w32Mouse.Y;
}
专用void CreateDragDropWindow(可视dragElement)
{
这是._dragdropWindow=新窗口();
_dragdropWindow.WindowsStyle=WindowsStyle.None;
_dragdropWindow.AllowTransparency=true;
using System.ComponentModel;
using System.Windows.Controls;
namespace TestWpfPure
{
/// <summary>
/// Interaction logic for Card.xaml
/// </summary>
public partial class Card : UserControl, INotifyPropertyChanged
{
private string text;
public string Text
{
get
{
return this.text;
}
set
{
this.text = value;
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs("Text"));
}
}
public Card()
{
InitializeComponent();
DataContext = this;
}
public event PropertyChangedEventHandler PropertyChanged;
}
}