WPF实现TreeView项的拖动及右键菜单
项目需求背景,用一个TreeView控件实现一个部门的层级显示,当需要把一个部门移动到另一个部门时,我们只需要把部门按层级展开,把源部门拖动到目标部门,然后根据需要的功能实现相应的鼠标右键功能。
1、创建一个部门类Department public class Department { public int ID { get; set; } public int ParentID { get; set; }
public string Name { get; set; }
public List<Department> Departments;
public Department(int id, int parentid, string name)
{ ID = id; ParentID = parentid; Name = name; Departments = new List<Department>(); } } 2、一个公共方法类 CommanClass public class CommanClass { public List<Department> DepartmentCollection; public CommanClass() { DepartmentCollection = CreateOrignDepartments(); } public List<Department> CreateOrignDepartments() { List<Department> departs = new List<Department>(); departs.Add(new Department(1, 0, "大学")); departs.Add(new Department(2, 1, "理学院")); departs.Add(new Department(3, 1, "工学院")); departs.Add(new Department(4, 1, "文学院")); departs.Add(new Department(5, 2, "数学系")); departs.Add(new Department(6, 2, "物理系")); departs.Add(new Department(7, 3, "机械工程系")); departs.Add(new Department(8, 3, "土木工程系")); departs.Add(new Department(9, 3, "电子自动化系")); departs.Add(new Department(10, 4, "外语系")); departs.Add(new Department(11, 4, "古文学系")); departs.Add(new Department(12, 4, "历史系")); departs.Add(new Department(13, 4, "中文系")); return departs; } // 创建层级结构的根节点 public void CreateTreeView(TreeView treeView)
{ foreach (var d in DepartmentCollection) { if (d.ParentID == 0) { TreeViewItem rootItem = new TreeViewItem(); rootItem.Header = d.Name; rootItem.Tag = d; treeView.Items.Add(rootItem); CreateTreeViewItem(rootItem,d); } } } // 创建层级结构的子节点 private void CreateTreeViewItem(TreeViewItem childItem,Department parent)
{ foreach (var d in DepartmentCollection) { if (d.ParentID == parent.ID) { TreeViewItem child = new TreeViewItem(); child.Header = d.Name; child.Tag = d; childItem.Items.Add(child); CreateTreeViewItem(child, d); } } } } 3、前台页面 <Grid> <TreeView Name="treeView" Width="200" AllowDrop="True"> <TreeView.ContextMenu> <ContextMenu Name="tvMenu" Width="120" HorizontalAlignment="Left" VerticalAlignment="Top"> <MenuItem Header="添加" Name="miAdd"/> <MenuItem Header="删除" Name="miDel"/> </ContextMenu> </TreeView.ContextMenu> </TreeView> </Grid> 4、后台实现拖拽方法 首先需要把部门层级加载出来,只需调用CommanClass类的CreateTreeView方法即可 实现拖拽需要用到DragOver、Drop和MouseMove事件 treeView.MouseMove += new MouseEventHandler(treeView_MouseMove); treeView.DragOver += new DragEventHandler(treeView_DragOver); treeView.Drop += new DragEventHandler(treeView_Drop); 三个公共变量 private Point _LastMouseDown;//鼠标按下的位置 private TreeViewItem draggedItem, _target; //鼠标拖动项和存放的目标项 //实现treeView.DragOver 事件 void treeView_DragOver(object sender, DragEventArgs e) { try { Point currentPosition = e.GetPosition(treeView); if ((Math.Abs(currentPosition.X - _LastMouseDown.X) > 10.0) || (Math.Abs(currentPosition.Y - _LastMouseDown.Y) > 10.0))
{ TreeViewItem item = GetNearestContainer(e.OriginalSource as UIElement); e.Effects = CheckDropTarget(draggedItem, item) ? DragDropEffects.Move : DragDropEffects.None;
} e.Handled = true; } catch { } } //获取TreeViewItem private TreeViewItem GetNearestContainer(UIElement element) { TreeViewItem container = element as TreeViewItem; while ((container == null) && (element != null))
{ element = VisualTreeHelper.GetParent(element) as UIElement; container = element as TreeViewItem; } return container; } // 判断源项和目标项是否是自己本身 private bool CheckDropTarget(TreeViewItem sourceItem, TreeViewItem targetItem) { bool isEqual = false; if (sourceItem != null && targetItem != null) { if (!sourceItem.Header.ToString().Equals(targetItem.Header.ToString())) { isEqual = true; } } return isEqual; } 实现treeView.Drop 事件 void treeView_Drop(object sender, DragEventArgs e) { try { e.Effects = DragDropEffects.None; e.Handled = true; TreeViewItem targetItem = GetNearestContainer(e.OriginalSource as UIElement);
if (targetItem != null && draggedItem != null)
{ _target = targetItem; e.Effects = DragDropEffects.Move; } } catch { } } //实现 treeView.MouseMove 事件 void treeView_MouseMove(object sender, MouseEventArgs e) { try { if (e.LeftButton == MouseButtonState.Pressed) { Point currentPoint = e.GetPosition(treeView); if ((Math.Abs(currentPoint.X - _LastMouseDown.X) > 10.0) || (Math.Abs(currentPoint.Y - _LastMouseDown.Y) > 10.0))
{ draggedItem = (TreeViewItem)treeView.SelectedItem; if (draggedItem != null) { DragDropEffects finalDropEffect = DragDrop.DoDragDrop(treeView, treeView.SelectedValue, DragDropEffects.Move); if ((finalDropEffect == DragDropEffects.Move) && _target != null)
{ if (!draggedItem.Header.ToString().Equals(_target.Header.ToString())) { CopyItem(draggedItem, _target); _target = null; draggedItem = null; } } } } } } catch { } } private void CopyItem(TreeViewItem sourceItem, TreeViewItem targetItem) { if (MessageBox.Show("是否将<" + sourceItem.Header.ToString() + ">移动到<" + targetItem.Header.ToString() + ">之下?", "询问",MessageBoxButton.YesNo , MessageBoxImage.Question) == MessageBoxResult.Yes) { AddChildFromDropItem(sourceItem, targetItem); TreeViewItem parentItem = FindVisualParent<TreeViewItem>(sourceItem);
//在源项的父项中移除源项 if (parentItem == null)
treeView.Items.Remove(sourceItem); else parentItem.Items.Remove(sourceItem); } } //把源项及其子项移动到目标项 private void AddChildFromDropItem(TreeViewItem sourceItem, TreeViewItem targetItem) { if (sourceItem != null && targetItem != null) { TreeViewItem addItem = new TreeViewItem(); addItem.Header = sourceItem.Header; addItem.Tag = sourceItem.Tag; Department source = addItem.Tag as Department; Department target = targetItem.Tag as Department; if (source != null && target != null) { source.ParentID = target.ID; } targetItem.Items.Add(addItem);
foreach (TreeViewItem item in sourceItem.Items) { AddChildFromDropItem(item, addItem); } } } //找到需要拖拽项的父项 private T FindVisualParent<T>(UIElement child) where T : UIElement { if (child == null) return null; UIElement parent = VisualTreeHelper.GetParent(child) as UIElement;
while (parent != null) { T found = parent as T; if (found != null) return found; else parent = VisualTreeHelper.GetParent(parent) as UIElement; } return null; } 最后实现右键菜单只需要在Loaded事件中加载MenuItem的Click事件就行 例如删除右键 miDel.Click += new RoutedEventHandler(miDel_Click); void miDel_Click(object sender, RoutedEventArgs e) { //throw new NotImplementedException(); } 最后实现效果 |
|