作为一名程序员,相信大家都已经接触过大名鼎鼎的原型设计工具Axure,没用过的一定要去了解一下,本文要使用WPF实现树控件节点拖动功能。
原理:树节点由图片和文本构成,当拖动节点移动到目标节点的图片上时认为是拖动到目标节点的同级目录;当拖动节点到目标节点的文本上时认为是拖动到目标节点的子目录。使用EventSetter和事件实现标识是拖动到目标节点同级目录,还是拖动到目标节点子目录功能;DataTrigger实现拖动到图片上和文本上的节点显示效果。
前台代码:
后台代码:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
namespace DragTree
{
///
/// MainWindow.xaml 的交互逻辑
///
public partial class MainWindow : Window
{
#region
private bool IsDrop = false;
private ObservableCollection list = new ObservableCollection();
#endregion
public MainWindow()
{
InitializeComponent();
InitTree();
}
#region
///
/// 树控件数据初始化
///
public void InitTree()
{
var folder = GetBitmapImage("folder.png");
var file = GetBitmapImage("file.png");
// 根节点
var root = new TreeItem()
{
Name = "root",
Childern = list
};
var ti = new TreeItem()
{
BI = folder,
Name = "文件夹1",
Parent = root,
Childern = new ObservableCollection()
};
var tmp11 = new TreeItem()
{
BI = folder,
Name = "文件夹11",
Parent = ti,
Childern = new ObservableCollection()
};
var tmp111 = new TreeItem()
{
BI = file,
Name = "文件111",
Parent = tmp11,
Childern = new ObservableCollection()
};
tmp11.Childern.Add(tmp111);
var tmp112 = new TreeItem()
{
BI = file,
Name = "文件112",
Parent = tmp11,
Childern = new ObservableCollection()
};
tmp11.Childern.Add(tmp112);
var tmp113 = new TreeItem()
{
BI = file,
Name = "文件113",
Parent = tmp11,
Childern = new ObservableCollection()
};
tmp11.Childern.Add(tmp113);
ti.Childern.Add(tmp11);
var tmp12 = new TreeItem()
{
BI = folder,
Name = "文件夹12",
Parent = ti,
Childern = new ObservableCollection()
};
ti.Childern.Add(tmp12);
var tmp13 = new TreeItem()
{
BI = folder,
Name = "文件夹13",
Parent = ti,
Childern = new ObservableCollection()
};
ti.Childern.Add(tmp13);
list.Add(ti);
this.treeView.ItemsSource = list;
}
private Point _lastMouseDown;
private void tvRequire_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
var ele = e.OriginalSource as FrameworkElement;
if (ele != null)
{
_lastMouseDown = e.GetPosition(treeView);
moveTreeItem = (TreeItem)ele.DataContext;
}
}
}
private TreeItem moveTreeItem;
private void tvRequire_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Point currentPosition = e.GetPosition(treeView);
if ((Math.Abs(currentPosition.X - _lastMouseDown.X) > 2.0) || (Math.Abs(currentPosition.Y - _lastMouseDown.Y) > 2.0))
{
if (!IsDrop)
{
if (moveTreeItem != null)
{
IsDrop = true;
this.treeView.Cursor = Cursors.Hand;
}
}
}
}
}
private void tvRequire_MouseUp(object sender, MouseEventArgs e)
{
if (moveTreeItem == null)
{
return;
}
var ele = e.OriginalSource as FrameworkElement;
if (ele != null)
{
var targetTreeItem = (TreeItem)ele.DataContext;
if (targetTreeItem == null)
{
ClearTreeDrop();
return;
}
if (targetTreeItem.Name != moveTreeItem.Name)
{
if (targetTreeItem.IsAddIn)
{
#region 移动到目标子集
var tmp = targetTreeItem.Childern.SingleOrDefault(l => l.Name == moveTreeItem.Name);
if (tmp == null)
{
moveTreeItem.Parent.Childern.Remove(moveTreeItem);
moveTreeItem.Parent = targetTreeItem;
AddIn(targetTreeItem, moveTreeItem);
}
targetTreeItem.IsAddIn = false;
#endregion
}
else if (targetTreeItem.IsAdd)
{
#region 移动到目标同级
moveTreeItem.Parent.Childern.Remove(moveTreeItem);
Add(targetTreeItem.Parent, targetTreeItem, moveTreeItem);
targetTreeItem.IsAdd = false;
#endregion
}
}
}
ClearTreeDrop();
}
private void AddIn(TreeItem argTarget, TreeItem argMove)
{
if (argTarget != null)
{
var sortList = new List();
sortList.Add(argMove);
foreach (var item in argTarget.Childern)
{
sortList.Add(item);
}
argTarget.Childern.Clear();
foreach (var item in sortList)
{
argTarget.Childern.Add(item);
}
}
}
private void Add(TreeItem argParent, TreeItem argTarget, TreeItem argMove)
{
if (argParent != null)
{
var sortList = new List();
foreach (var item in argParent.Childern)
{
sortList.Add(item);
if (item.Name == argTarget.Name)
{
argMove.Parent = item.Parent;
sortList.Add(argMove);
}
}
argParent.Childern.Clear();
foreach (var item in sortList)
{
argParent.Childern.Add(item);
}
}
}
private void tvRequire_MouseLeave(object sender, MouseEventArgs e)
{
ClearTreeDrop();
}
private void ClearTreeDrop()
{
moveTreeItem = null;
IsDrop = false;
this.treeView.Cursor = Cursors.Arrow;
}
public BitmapImage GetBitmapImage(string argName, string argCatalog = null)
{
try
{
string path = string.Empty;
if (string.IsNullOrEmpty(argCatalog))
{
path = @"pack://application:,,,/Image/" + argName;
}
else
{
path = @"pack://application:,,,/Image/" + argCatalog + "/" + argName;
}
var bi = new BitmapImage();
bi.BeginInit();
// 创建 BitmapImage 后关闭流,请将 CacheOption 属性设置为 BitmapCacheOption.OnLoad。
// 默认 OnDemand 缓存选项保留对流的访问,直至需要位图并且垃圾回收器执行清理为止。
bi.CacheOption = BitmapCacheOption.OnLoad;
bi.UriSource = new Uri(path);
bi.EndInit();
bi.Freeze();
return bi;
}
catch (Exception ex)
{
return null;
}
}
private void Image_MouseEnter(object sender, MouseEventArgs e)
{
var ele = e.OriginalSource as Image;
if (ele != null)
{
Console.WriteLine("Image_MouseEnter");
var ti = (TreeItem)ele.DataContext;
if (ti != null)
{
if (IsDrop)
{
ti.IsAdd = true;
}
}
}
}
private void Image_MouseLeave(object sender, MouseEventArgs e)
{
var ele = e.OriginalSource as Image;
if (ele != null)
{
Console.WriteLine("Image_MouseLeave");
var ti = ele.DataContext as TreeItem;
if (ti != null)
{
ti.IsAdd = false;
}
}
}
private void TextBlock_MouseEnter(object sender, MouseEventArgs e)
{
var ele = e.OriginalSource as TextBlock;
if (ele != null)
{
Console.WriteLine("TextBlock_MouseEnter");
var ti = (TreeItem)ele.DataContext;
if (ti != null)
{
if (IsDrop)
{
ti.IsAddIn = true;
}
}
}
}
private void TextBlock_MouseLeave(object sender, MouseEventArgs e)
{
var ele = e.OriginalSource as TextBlock;
if (ele != null)
{
Console.WriteLine("TextBlock_MouseLeave");
var ti = (TreeItem)ele.DataContext;
if (ti != null)
{
ti.IsAddIn = false;
}
}
}
#endregion
#region
public class TreeItem : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
///
/// 节点显示的图片
///
public BitmapImage BI { get; set; }
///
/// 节点显示的文本
///
public string Name { get; set; }
///
/// 节点类型
///
public string Type { get; set; }
///
/// 父节点
///
public TreeItem Parent { get; set; }
///
/// 子节点集合
///
public ObservableCollection Childern { get; set; }
private bool m_isAdd = false;
///
/// 拖动到目标节点时增加到同级目录标志
///
public bool IsAdd
{
get { return m_isAdd; }
set
{
if (m_isAdd != value)
{
m_isAdd = value;
if (m_isAdd)
{
IsAddIn = false;
}
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsAdd"));
}
}
}
}
private bool m_isAddin = false;
///
/// 拖动到目标节点时增加到子目录标志
///
public bool IsAddIn
{
get { return m_isAddin; }
set
{
if (m_isAddin != value)
{
m_isAddin = value;
if (m_isAddin)
{
m_isAdd = false;
}
//触发事件
if (PropertyChanged != null)
{
PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsAddIn"));
}
}
}
}
}
#endregion
}
}