效果图:
(1) DataItem类的用于创建项目SurfaceListBox控制。它有两个属性:
Name:Item名
CanDrop: 指定的项目是否可以删除目标控制
public class DataItem
{
private string name;
private bool canDrop;
public string Name
{
get { return name; }
}
public bool CanDrop
{
get { return canDrop; }
}
public DataItem(string name, bool canDrop)
{
this.name = name;
this.canDrop = canDrop;
}
}
(2) DataTemplate对象(数据外衣)指定每个项目的布局,并将Name属性和CanDrop属性的内容两个相应的标签控件。
<s:SurfaceWindow x:Class="DraggingAndDroppingBetweenSurfaceListBoxes.SurfaceWindow1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:s="http://schemas.microsoft.com/surface/2008"
Title="DraggingAndDroppingBetweenSurfaceListBoxes"
>
<s:SurfaceWindow.Resources>
<DataTemplate x:Key="SurfaceListBoxItemDataTemplate">
<StackPanel Height="120" Width="190" Background="Gray">
<Label
Content="{Binding Name}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="20"/>
<Label
Content="{Binding CanDrop}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="18"/>
</StackPanel>
</DataTemplate>
</s:SurfaceWindow.Resources>
<Grid>
</Grid>
</s:SurfaceWindow>
(3) 两个ObservableCollection对象来保存数据项定义。这个集合是暴露通过公共属性,定义在后台代码文件为主要SurfaceWindow对象。
sourceItems: Item数据源列表框
TargetItems: Item拖放至列表框
注意:需要引用using System.Collections.ObjectModel;
private ObservableCollection<DataItem> sourceItems;
private ObservableCollection<DataItem> targetItems;
/// <summary>
/// Items that bind with the drag source list box.
/// </summary>
public ObservableCollection<DataItem> SourceItems
{
get
{
if (sourceItems == null)
{
sourceItems = new ObservableCollection<DataItem>();
}
return sourceItems;
}
}
/// <summary>
/// Items that bind with the drop target list box.
/// </summary>
public ObservableCollection<DataItem> TargetItems
{
get
{
if (targetItems == null)
{
targetItems = new ObservableCollection<DataItem>();
}
return targetItems;
}
}
}
(4) 初始化数据(向SourceItem集合中添加DataItem项)
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(e);
DataContext = this;
SourceItems.Add(new DataItem("Hammer", false));
SourceItems.Add(new DataItem("Saw", true));
SourceItems.Add(new DataItem("Pliers", true));
SourceItems.Add(new DataItem("Tape Measure", false));
SourceItems.Add(new DataItem("Square", true));
SourceItems.Add(new DataItem("Wrench", false));
SourceItems.Add(new DataItem("Screwdriver", true));
SourceItems.Add(new DataItem("Plumb Bob", true));
SourceItems.Add(new DataItem("Miter Box", false));
SourceItems.Add(new DataItem("Knife", true));
SourceItems.Add(new DataItem("Chisel", true));
SourceItems.Add(new DataItem("Punch", true));
}
(5) 创建SurfaceListBox控制和绑定的物品
DragSource:被拖拽SurfaceListbox集合
DropTarget:被放置的surfaceListBox集合
重点是:PreviewTouchDown事件和SurfaceDragDrop的四个事件:DragCompleted,DragEnter,DragLeave,Drop
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<s:SurfaceListBox
Name="DragSource"
Grid.Column="0"
Width="250"
BorderBrush="{DynamicResource {x:Static s:SurfaceColors.ListBoxItemBackgroundBrushKey}}"
ItemTemplate="{StaticResource SurfaceListBoxItemDataTemplate}"
ItemsSource="{Binding Path=SourceItems}"
PreviewTouchDown="OnDragSourcePreviewTouchDown"
s:SurfaceDragDrop.DragCompleted="OnDragCompleted"/>
<s:SurfaceListBox
Name="DropTarget"
Grid.Column="1"
AllowDrop="True"
Width="250"
BorderBrush="{DynamicResource {x:Static s:SurfaceColors.ListBoxItemBackgroundBrushKey}}"
ItemTemplate="{StaticResource SurfaceListBoxItemDataTemplate}"
ItemsSource="{Binding Path=TargetItems}"
s:SurfaceDragDrop.DragEnter="OnDropTargetDragEnter"
s:SurfaceDragDrop.DragLeave="OnDropTargetDragLeave"
s:SurfaceDragDrop.Drop="OnDropTargetDrop"/>
</Grid>
(6) CarsorStyle(光标风格设置)目标对象被选中时边框颜色为黄色。拖动目标对象之另外一个surfaceListbox对象中呈现绿色说明可以被放入,呈现红色说明不能不放入。
<Style x:Key="CursorStyle" TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate" Value="{StaticResource SurfaceListBoxItemDataTemplate}" />
<Setter Property="BorderThickness" Value="9"/>
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static s:SurfaceColors.Accent1BrushKey}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<Border
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}">
<ContentPresenter Margin="0"
Content="{TemplateBinding Content}"
ContentTemplate="{TemplateBinding ContentTemplate}">
</ContentPresenter>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Tag" Value="CanDrop">
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static s:SurfaceColors.Accent4BrushKey}}" />
</Trigger>
<Trigger Property="Tag" Value="CannotDrop">
<Setter Property="BorderBrush" Value="{DynamicResource {x:Static s:SurfaceColors.Accent3BrushKey}}" />
</Trigger>
</Style.Triggers>
</Style>
(7) PreviewTouchDown事件
详细见代码内部文档注释:
private void OnDragSourcePreviewTouchDown(object sender, TouchEventArgs e)
{
//获取当前触摸对象转换成FrameworkElement
FrameworkElement findSource = e.OriginalSource as FrameworkElement;
//new一个draggedElement初始化为null
SurfaceListBoxItem draggedElement = null;
// Find the touched SurfaceListBoxItem object.
while (draggedElement == null && findSource != null)
{
if ((draggedElement = findSource as SurfaceListBoxItem) == null)
{
findSource = VisualTreeHelper.GetParent(findSource) as FrameworkElement;
}
}
if (draggedElement == null)
{
return;
}
// Create the cursor visual.
ContentControl cursorVisual = new ContentControl()
{
Content = draggedElement.DataContext,
Style = FindResource("CursorStyle") as Style
};
// Add a handler. This will enable the application to change the visual cues.
SurfaceDragDrop.AddTargetChangedHandler(cursorVisual, OnTargetChanged);
// Create a list of input devices. Add the touches that
// are currently captured within the dragged element and
// the current touch (if it isn't already in the list).
List<InputDevice> devices = new List<InputDevice>();
devices.Add(e.TouchDevice);
foreach (TouchDevice touch in draggedElement.TouchesCapturedWithin)
{
if (touch != e.TouchDevice)
{
devices.Add(touch);
}
}
// Get the drag source object
ItemsControl dragSource = ItemsControl.ItemsControlFromItemContainer(draggedElement);
SurfaceDragCursor startDragOkay =
SurfaceDragDrop.BeginDragDrop(
dragSource, // The SurfaceListBox object that the cursor is dragged out from.
draggedElement, // The SurfaceListBoxItem object that is dragged from the drag source.
cursorVisual, // The visual element of the cursor.
draggedElement.DataContext, // The data associated with the cursor.
devices, // The input devices that start dragging the cursor.
DragDropEffects.Move); // The allowed drag-and-drop effects of the operation.
// If the drag began successfully, set e.Handled to true.
// Otherwise SurfaceListBoxItem captures the touch
// and causes the drag operation to fail.
e.Handled = (startDragOkay != null);
}
(8) DragEnter事件
private void OnDropTargetDragEnter(object sender, SurfaceDragDropEventArgs e)
{
//获取DataItem类数据
DataItem data = e.Cursor.Data as DataItem;
//获取CanDrop中的值
if (!data.CanDrop)
{
//不能被放置到拖动的集合中
e.Effects = DragDropEffects.None;
}
}
(9) DragLeave事件
private void OnDropTargetDragLeave(object sender, SurfaceDragDropEventArgs e)
{
// Reset the effects.
e.Effects = e.Cursor.AllowedEffects;
}
(10)OnTargetChanged方法(PreviewTouchDown调用了该方法)
private void OnTargetChanged(object sender, TargetChangedEventArgs e)
{
if (e.Cursor.CurrentTarget != null)
{
DataItem data = e.Cursor.Data as DataItem;
e.Cursor.Visual.Tag = (data.CanDrop) ? "CanDrop" : "CannotDrop";
}
else
{
e.Cursor.Visual.Tag = null;
}
}
(11) Drop事件 当一个条目(即允许下降)是掉在目标SurfaceListBox控制,DropEvent事件引发时。事件处理程序添加数据在光标到TargetItems集合,绑定到该控件。
private void OnDropTargetDrop(object sender, SurfaceDragDropEventArgs e)
{
TargetItems.Add(e.Cursor.Data as DataItem);
}
(12)DragCompleted事件当目标Item移动到被放置的Listbox中删除原目标元素的Item元素项
private void OnDragCompleted(object sender, SurfaceDragCompletedEventArgs e)
{
// If the operation is Move, remove the data from drag source.
if (e.Cursor.Effects == DragDropEffects.Move)
{
SourceItems.Remove(e.Cursor.Data as DataItem);
}
}
参考链接:http://msdn.microsoft.com/en-us/library/ff727837.aspx