WPF 可拖动的ListView
这是一个很简单的程序,致力于快速打开 exe 执行文件,方便删除与新增,同时还可以拖拽 listviewitem 进行更新优先级
用途
- 书签
- 笔记
- 歌单
- 排班
支持功能
- 批量多选
- 打开执行程序
- 删除列表
- 保存状态
- 拖动效果
- xml 读取与更新
# 读取xml文件
public void Read()
{
Task.Factory.StartNew(() =>
{
XmlDocument xml = new XmlDocument();
xml.Load(Path.Combine(baseDir, "Data.xml"));
var Item = xml.SelectSingleNode("exeTer");
XmlNodeList node = Item.ChildNodes;
foreach (XmlNode item in node)
{
XmlElement _xml = (XmlElement)item;
var _path = _xml.GetAttribute("Path");
var _fileName = _xml.GetAttribute("FileName");
var _xmlmodel = new List<Exeter>();
App.Current.Dispatcher.InvokeAsync(() =>
{
ExeterItems.Add(new Exeter()
{
Path = _path,
FileName = _fileName,
});
});
}
});
}
# 保存和更新
private void SaveUpdate(List<Exeter> exeters)
{
List<Exeter> _list = new List<Exeter>();
XmlDocument xml = new XmlDocument();
var xmlpath = Path.Combine(baseDir, "Data.xml");
xml.Load(xmlpath);
var Item = xml.SelectSingleNode("exeTer");
var length = Item.ChildNodes.Count;
for (int i = length - 1; i >= 0; i--)
{
XmlElement _xml = (XmlElement)Item.ChildNodes[i];
var _fileName = _xml.GetAttribute("FileName");
var ishas = exeters.Any(p => p.FileName == _fileName);
if (ishas)
{
Item.RemoveChild(_xml);
}
}
foreach (var item in exeters)
{
XmlElement unit = xml.CreateElement("AUnit");
unit.SetAttribute("Path", item.Path);
unit.SetAttribute("FileName", item.FileName);
Item.AppendChild(unit);
}
xml.Save(xmlpath);
}
在 Microsoft.Xaml.Behaviors.Wp 扩展中使用了 InvokeCommandAction
<ToggleButton
x:Name="tgBtn"
Width="120"
Height="30"
Content="{Binding CheckName}"
IsChecked="False">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Checked">
<i:InvokeCommandAction Command="{Binding OpenDropCmd}" />
</i:EventTrigger>
<i:EventTrigger EventName="Unchecked">
<i:InvokeCommandAction Command="{Binding CloseDropCmd}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</ToggleButton>
拖动效果
<ListView
x:Name="exelist"
AllowDrop="True"
ItemsSource="{Binding ExeterItems}"
PreviewDragEnter="Exelist_DragEnter"
PreviewDragLeave="Exelist_DragLeave"
PreviewDrop="Exelist_Drop"
PreviewMouseDown="Exelist_PreviewMouseDown"
PreviewQueryContinueDrag="Exelist_QueryContinueDrag"
ScrollViewer.VerticalScrollBarVisibility="Visible"
Style="{StaticResource Bauble.Styles.ListView}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid ToolTip="{Binding Path}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<TextBlock
VerticalAlignment="Center"
FontSize="20"
Foreground="White"
Text="{Binding FileName}" />
<Button
Grid.Column="1"
Width="50"
Margin="5"
Command="{Binding DataContext.OpenCmd, RelativeSource={RelativeSource AncestorType={x:Type ListView}, Mode=FindAncestor}}"
CommandParameter="{Binding}"
Content="打开" />
<Button
Grid.Column="2"
Width="50"
Margin="0,0,5,0"
Command="{Binding DataContext.DeletedCmd, RelativeSource={RelativeSource AncestorType={x:Type ListView}, Mode=FindAncestor}}"
CommandParameter="{Binding}"
Content="删除" />
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
private void Exelist_DragLeave(object sender, DragEventArgs e)
{
if (tgBtn.IsChecked == true)
{
e.Effects = DragDropEffects.None;
Point pos = e.GetPosition(exelist);
HitTestResult result = VisualTreeHelper.HitTest(exelist, pos);
if (result == null)
return;
ListViewItem selectedItem = VisualObjectHelper.FindVisualParent<ListViewItem>(result.VisualHit);
if (selectedItem != null)
selectedItem.IsSelected = false;
}
}
private void Exelist_DragEnter(object sender, DragEventArgs e)
{
if (tgBtn.IsChecked == true)
{
e.Effects = DragDropEffects.Copy;
Point pos = e.GetPosition(exelist);
HitTestResult result = VisualTreeHelper.HitTest(exelist, pos);
if (result == null)
return;
ListViewItem selectedItem = VisualObjectHelper.FindVisualParent<ListViewItem>(result.VisualHit);
if (selectedItem != null)
selectedItem.IsSelected = true;
}
}
# 持续拖动,不停的更新
private void Exelist_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
{
if (mAdornerLayer == null)
return;
System.Diagnostics.Debug.WriteLine($"Exelist_QueryContinueDrag {DateTime.Now.ToString("HH-mm-ss fff")}");
mAdornerLayer.Update();
}
# 切换到拖动模式下,阻止隧道模式向内传递事件
private void Exelist_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (tgBtn.IsChecked == true)
{
e.Handled = true;
if (e.LeftButton != MouseButtonState.Pressed)
return;
Point pos = e.GetPosition(exelist);
HitTestResult result = VisualTreeHelper.HitTest(exelist, pos);
if (result == null)
return;
ListViewItem treeViewItem = VisualObjectHelper.FindVisualParent<ListViewItem>(result.VisualHit); // Find your actual visual you want to drag
if (treeViewItem == null || treeViewItem.DataContext == null)
return;
//if ((treeViewItem.DataContext as Exeter)?.ItemList.Count > 0)
// return;
Exeter dataItem = treeViewItem.DataContext as Exeter;
if (string.IsNullOrEmpty(dataItem.FileName) || !Path.HasExtension(dataItem.Path))
return;
DragDropAdorner adorner = new DragDropAdorner(treeViewItem);
mAdornerLayer = AdornerLayer.GetAdornerLayer(exelist);
mAdornerLayer.Add(adorner);
DataObject dataObject = new DataObject(dataItem);
//DoDragDrop 会处理 Exelist_DragLeave 和 Exelist_DragEnter
DragDrop.DoDragDrop(exelist, dataObject, DragDropEffects.Copy);
mAdornerLayer?.Remove(adorner);
mAdornerLayer = null;
}
}