C# WPF ListView 拖放自定义项





5.00/5 (9投票s)
本文档解释了如何在 WPF 技术中,在 ListView 控件内实现自定义项目的拖放功能。
引言
本文档将逐步展示如何在 ListView
对象中实现拖放功能,以改变当前选中项目的呈现顺序。行项目使用自定义类定义。还将展示如何使用两个按钮移动项目。
图 1 - “行 3” 已从最后一个位置移动到第一个位置
Using the Code
创建一个新项目,并在定义主窗口的 XAML 代码编辑器中插入此代码,以添加一对按钮和一个 ListView
对象。在 ListView
对象中,重要的是设置此属性 AllowDrop = "True"
, 否则拖放功能将不会启用。
<Button x:Name="btnUp" Content="Move Up" HorizontalAlignment="Left" Height="28"
Margin="10,12,0,0" VerticalAlignment="Top" Width="68" Click="btnUp_Click"/>
<Button x:Name="btnDown" Content="Move Dn" HorizontalAlignment="Left" Height="28"
Margin="83,12,0,0" VerticalAlignment="Top" Width="68" Click="btnDown_Click"/>
<ListView Margin="10,50,10,10" Name="lstView" BorderBrush="WhiteSmoke"
AllowDrop="True" PreviewMouseLeftButtonDown="lstView_PreviewMouseLeftButtonDown"
MouseMove="lstView_MouseMove" DragEnter="lstView_DragEnter" Drop="lstView_Drop">
<ListView.View>
<GridView>
<GridViewColumn Header="Sel." Width="32">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}"/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="Title" Width="120" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Header="Note" Width="150" DisplayMemberBinding="{Binding Note}" />
</GridView>
</ListView.View>
</ListView>
代码 1 - 此 XAML 代码必须插入在 <Grid></Grid> 数据块之间。
创建一个新类并添加以下代码
public class WorkItem
{
public bool IsSelected { get; set; }
public string Title { get; set; }
public string Note { get; set; }
public WorkItem(bool isSelected, string title, string note)
{
this.IsSelected = isSelected;
this.Title = title;
this.Note = note;
}
}
这个类是代表 ListView
对象的数据项的模型。要显示你的自定义项目,你必须修改 WorkItem
类的属性和 XAML 代码,以定义你的数据列以及正确的数据绑定到你的自定义类。
打开主窗口的代码编辑器,并在 using
部分添加以下代码
using System.Collections.ObjectModel; // ObservableCollection class
项目列表将通过 ObservableCollection
对象进行管理,因为该对象暴露了使在集合中移动项目更容易的方法。
在窗口类级别添加以下 private
变量。
private Point startPoint = new Point();
private ObservableCollection<WorkItem> Items = new ObservableCollection<WorkItem>();
private int startIndex = -1;
为了在 ListView
控件中插入测试数据,请从类构造函数中调用 InitializeListView();
函数,例如在调用标准函数 InitializeComponent();
之后。
private void InitializeListView()
{
// Clear data
lstView.Items.Clear();
Items.Clear();
// Add rows
Items.Add(new WorkItem(true, "Row 1", "First orw"));
Items.Add(new WorkItem(false, "Row 2", "Second row"));
Items.Add(new WorkItem(true, "Row 3", "Third row"));
lstView.ItemsSource = Items;
}
添加以下代码以实现与屏幕对象关联的事件。使用 btnUp
和 btnDown
按钮,你可以移动 ListView
控件中的选中项目,而无需使用拖放功能。
private void lstView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// Get current mouse position
startPoint = e.GetPosition(null);
}
// Helper to search up the VisualTree
private static T FindAnchestor<T>(DependencyObject current)
where T : DependencyObject
{
do
{
if (current is T)
{
return (T)current;
}
current = VisualTreeHelper.GetParent(current);
}
while (current != null);
return null;
}
private void lstView_MouseMove(object sender, MouseEventArgs e)
{
// Get the current mouse position
Point mousePos = e.GetPosition(null);
Vector diff = startPoint - mousePos;
if (e.LeftButton == MouseButtonState.Pressed &&
(Math.Abs(diff.X) > SystemParameters.MinimumHorizontalDragDistance ||
Math.Abs(diff.Y) > SystemParameters.MinimumVerticalDragDistance))
{
// Get the dragged ListViewItem
ListView listView = sender as ListView;
ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
if (listViewItem == null) return; // Abort
// Find the data behind the ListViewItem
WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
if (item == null) return; // Abort
// Initialize the drag & drop operation
startIndex = lstView.SelectedIndex;
DataObject dragData = new DataObject("WorkItem", item);
DragDrop.DoDragDrop(listViewItem, dragData, DragDropEffects.Copy | DragDropEffects.Move);
}
}
private void lstView_DragEnter(object sender, DragEventArgs e)
{
if (!e.Data.GetDataPresent("WorkItem") || sender != e.Source)
{
e.Effects = DragDropEffects.None;
}
}
private void lstView_Drop(object sender, DragEventArgs e)
{
int index = -1;
if (e.Data.GetDataPresent("WorkItem") && sender == e.Source)
{
// Get the drop ListViewItem destination
ListView listView = sender as ListView;
ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
if (listViewItem == null)
{
// Abort
e.Effects = DragDropEffects.None;
return;
}
// Find the data behind the ListViewItem
WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
// Move item into observable collection
// (this will be automatically reflected to lstView.ItemsSource)
e.Effects = DragDropEffects.Move;
index = Items.IndexOf(item);
if (startIndex >=0 && index >= 0)
{
Items.Move(startIndex, index);
}
startIndex = -1; // Done!
}
}
private void btnUp_Click(object sender, RoutedEventArgs e)
{
WorkItem item = null;
int index = -1;
if (lstView.SelectedItems.Count != 1) return;
item = (WorkItem)lstView.SelectedItems[0];
index = Items.IndexOf(item);
if (index > 0)
{
Items.Move(index, index - 1);
}
}
private void btnDown_Click(object sender, RoutedEventArgs e)
{
WorkItem item = null;
int index = -1;
if (lstView.SelectedItems.Count != 1) return;
item = (WorkItem)lstView.SelectedItems[0];
index = Items.IndexOf(item);
if (index < Items.Count - 1)
{
Items.Move(index, index + 1);
}
}
就这样了!感谢您抽出时间阅读本文。如果您觉得它有用,请对其进行评分。
历史
- 版本 1.0.0 - 2018/03/26