在WPF应用程序中,ListView控件是展示数据列表的常用组件。为了提升用户体验,经常需要实现一些交互功能,比如拖放排序。本文将详细介绍如何在ListView控件中实现拖放排序功能,包括XAML布局和C#后端代码的编写。
拖放排序功能允许用户通过拖动列表项来重新排序列表。在WPF中,这可以通过设置ListView的AllowDrop属性为True,并处理相关的拖放事件来实现。下面将分步骤介绍如何实现这一功能。
首先,需要创建一个新的WPF项目,并在XAML代码编辑器中定义主窗口。将添加两个按钮和一个ListView对象。ListView对象需要设置AllowDrop属性为True,以启用拖放功能。
<Button x:Name="btnUp" Content="向上移动" HorizontalAlignment="Left" Height="28" Margin="10,12,0,0" VerticalAlignment="Top" Width="68" Click="btnUp_Click" />
<Button x:Name="btnDown" Content="向下移动" 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="选择" Width="32">
<GridViewColumn.CellTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding IsSelected}" />
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header="标题" Width="120" DisplayMemberBinding="{Binding Title}" />
<GridViewColumn Header="备注" Width="150" DisplayMemberBinding="{Binding Note}" />
</GridView>
</ListView.View>
</ListView>
这段XAML代码需要插入到<Grid></Grid>数据块之间。
接下来,需要定义一个数据模型来表示ListView中的数据项。将创建一个名为WorkItem的类,并添加相应的属性。
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代码,以定义数据列和正确的数据绑定到自定义类。
在主窗口的代码编辑器中,需要添加一些代码来初始化ListView控件。将使用ObservableCollection对象来管理项目列表,因为它提供了一些方法,使得在集合中移动项目变得更加容易。
private Point startPoint = new Point();
private ObservableCollection<WorkItem> Items = new ObservableCollection<WorkItem>();
private int startIndex = -1;
private void InitializeListView()
{
lstView.Items.Clear();
Items.Clear();
Items.Add(new WorkItem(true, "第一行", "第一行内容"));
Items.Add(new WorkItem(false, "第二行", "第二行内容"));
Items.Add(new WorkItem(true, "第三行", "第三行内容"));
lstView.ItemsSource = Items;
}
在类构造函数中,调用InitializeListView()函数来初始化ListView控件。
为了实现拖放排序功能,需要处理一些事件。使用btnUp和btnDown按钮,可以在ListView控件中移动选定的项目,而不需要使用拖放功能。
private void lstView_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
startPoint = e.GetPosition(null);
}
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)
{
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))
{
ListView listView = sender as ListView;
ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
if (listViewItem == null) return;
WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
if (item == null) return;
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)
{
ListView listView = sender as ListView;
ListViewItem listViewItem = FindAnchestor<ListViewItem>((DependencyObject)e.OriginalSource);
if (listViewItem == null)
{
e.Effects = DragDropEffects.None;
return;
}
WorkItem item = (WorkItem)listView.ItemContainerGenerator.ItemFromContainer(listViewItem);
index = Items.IndexOf(item);
e.Effects = DragDropEffects.Move;
if (startIndex >= 0 && index >= 0)
{
Items.Move(startIndex, index);
}
startIndex = -1;
}
}
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);
}
}