[译]Silverlight树控件增删改查和拖放
来自微软的Amit Dey提供了一个非常好的Sliverlight代码示例来展示了在Silverlight中树控件的增、删、改、查和拖放的功能。在Silverlight社区里面树控件的增、删、改、查是一个经常被问到的问题。但是我们收到还是有很多人请求得到这个代码示例。我们希望这个示例能够使开发人员轻松掌握这个典型的编程案例。
感谢Amit!
Silverlight树控件的增删改查
http://deyamit.wordpress.com/2011/02/14/silverlight-treeview-control-with-crud/
这是一个Silverlight树控件增、删、改、查操作的示例。除了这个之外它还支持节点的拖放功能。这篇文章需要你最少对Silverlight和数据绑定有一点基本的了解。我们最后的输出效果会像这样显示:
数据
首先我们来看一下要绑定到TreeView控件的数据结构
Node是要绑定到每一个TreeViewItem的类
Text表示节点上的显示的数据
Children表示节点的子节点,注意Node类的继承
System.ComponentModel.INOtifyPropertyChanged类按顺序保持UI在异步操作。阅读这篇文章可以更好的理解这个功能。
另外注意Add和Delete这两个帮助函数,分别用来添加和删除函数。
using System; using System.ComponentModel; using System.Collections.ObjectModel;
public class Node : INotifyPropertyChanged { private String text;
private ObservableCollection<Node> children;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<Node> Children { get { return children; } set { children = value; } }
public String Text { get { return text; } set { text = value; } }
public Node(String text) { Children = new ObservableCollection<Node>(); Text = text; }
public void Add(Node node) { children.Add(node); NotifyPropertyChanged("Children"); }
public void Delete(Node node) { children.Remove(node); NotifyPropertyChanged("Children"); }
private void NotifyPropertyChanged(String info) { if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(info)); } }
XAML
现在我们来看一下这个用户控件的XAML定义
第一步,我实现了一个右键菜单使增删改查更容易操作.你可以阅读这篇文章来学习右键菜单如何实现。
下一步,注意这两个HierarchicalDataTemplate,一个是TreeViewItem 在查看状态(TextBlock的变化),另一个是编辑状态(TextBox 的变化),TextBlock和TextBox绑定了Node的Text属性,我正在使用Silverlight Toolkitr的TreeViewDragDropTarget控件在父节点之间使用TreeViewItems进行拖放。
<UserControlxmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk"x:Class="CSSLTreeViewCRUDDragDrop.TreeViewCrudDragDrop"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"mc:Ignorable="d"d:DesignHeight="300" d:DesignWidth="400"xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"xmlns:mswindows="clr-namespace:Microsoft.Windows;assembly=System.Windows.Controls.Toolkit"> <UserControl.Resources> <!-- Template for Edit mode of TreeViewItem --><sdk:HierarchicalDataTemplate x:Key="TreeViewMainEditTemplate" ItemsSource="{Binding Children}"> <TextBox Text="{Binding Text,Mode=TwoWay}" > </TextBox> </sdk:HierarchicalDataTemplate> <!-- Template for Read mode for TreeViewItem --><sdk:HierarchicalDataTemplate x:Key="TreeViewMainReadTemplate"ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Text,Mode=TwoWay}"MouseRightButtonDown="TreeViewMain_MouseRightButtonDown"MouseRightButtonUp="TreeViewMain_MouseRightButtonUp"MouseLeftButtonDown="TreeViewMain_MouseLeftButtonDown" > </TextBlock> </sdk:HierarchicalDataTemplate> </UserControl.Resources> <Grid x:Name="LayoutRoot" Background="White"> <!-- TreeViewDragDropTarget from Toolkit to add DragAndDrop feature --><toolkit:TreeViewDragDropTarget AllowDrop="True"> <!-- Custom TreeView --><sdk:TreeView Name="TreeViewMain"ItemTemplate="{StaticResource TreeViewMainReadTemplate}"MouseRightButtonDown="TreeViewMain_MouseRightButtonDown"MouseRightButtonUp="TreeViewMain_MouseRightButtonUp"MouseLeftButtonDown="TreeViewMain_MouseLeftButtonDown"Width="400" Height="400" > </sdk:TreeView> </toolkit:TreeViewDragDropTarget> <!-- Context Menu --><Canvas> <Popup Name="ContextMenu" Visibility="Collapsed"> <Border BorderThickness="1" BorderBrush="Black" Background="White"> <StackPanel> <HyperlinkButton Content="Add" Name="AddButton" Click="AddButton_Click" /> <HyperlinkButton Content="Edit" Name="EditButton" Click="EditButton_Click"/> <HyperlinkButton Content="Delete" Name="DeleteButton" Click="DeleteButton_Click"/> </StackPanel> </Border> </Popup> </Canvas> </Grid> </UserControl>
后台代码
现在让我们先睹为快看一下用户控件的后台代码:
第一步,鼠标的事件处理程序,TreeViewItem的MouseRightButtonUp事件做两件事情,给选定的节点selectedNode分派指定的TreeViewItem数据上下文。
第二步,弹出右键菜单,选中节点selectedNode的信息是必需的,它作为引用被用来编辑TreeViewItem、添加子节点到TreeViewItem和删除TreeViewItem。
AddButton_Click事件处理程序,创建一个新的节点并当作节节点添加到选中的节点selecteNode的子节点下面。
EditButton_Click事件处理程序,改变选中节点的模板为编辑状态
DeleteButton_Click事件处理程序,首先确定TreeViewItem与选中的节点selectedNode关联,查找它的父节点,从父节点中删除选中的节点selectedNode。
using System; using System.Collections.Generic; using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Input; using System.Collections.ObjectModel; namespace CSSLTreeViewCRUDDragDrop { public partial class TreeViewCrudDragDrop : UserControl { ObservableCollection<Node> objectTree; Node selectedNode; public List<Node> Items { get { return objectTree.ToList<Node>(); } set { objectTree = new ObservableCollection<Node>(value); TreeViewMain.ItemsSource = objectTree; } } public TreeViewCrudDragDrop() { InitializeComponent(); objectTree = new ObservableCollection<Node>(); TreeViewMain.ItemsSource = objectTree; } private void TreeViewMain_MouseRightButtonDown(object sender, MouseButtonEventArgs e) { DisableEditForSelectedItem(); e.Handled = true; }
private void TreeViewMain_MouseRightButtonUp(object sender, MouseButtonEventArgs e) { DisableEditForSelectedItem(); if (sender is TextBlock) { selectedNode = (Node)((sender as TextBlock).DataContext); } else { selectedNode = null; } ShowContextMenu(e); }
private void TreeViewMain_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) { DisableEditForSelectedItem(); HideContextMenu(); }
private void AddButton_Click(object sender, RoutedEventArgs e) { Node newNode = new Node("New Node"); if (selectedNode != null) { selectedNode.Add(newNode); } else { if (objectTree != null) { objectTree.Add(newNode); } else { objectTree = new ObservableCollection<Node>(); objectTree.Add(newNode); } } HideContextMenu(); } private void EditButton_Click(object sender, RoutedEventArgs e) { EnalbleEditForSelectedItem(); TreeViewItem selectedTreeViewItem =
TreeViewExtensions.GetContainerFromItem(TreeViewMain, selectedNode);
HideContextMenu(); }
private void DeleteButton_Click(object sender, RoutedEventArgs e) { TreeViewItem selectedTreeViewItem = TreeViewExtensions.GetContainerFromItem(TreeViewMain, selectedNode); if (selectedTreeViewItem != null) { TreeViewItem selectedTreeViewItemParent = TreeViewExtensions.GetParentTreeViewItem(selectedTreeViewItem);
if (selectedTreeViewItemParent != null) { Node seleactedParentNode = (Node)selectedTreeViewItemParent.DataContext;
seleactedParentNode.Delete(selectedNode);
} else { objectTree.Remove(selectedNode); }
}
HideContextMenu(); }
private void ShowContextMenu(MouseButtonEventArgs e) { e.Handled = true; Point p = e.GetPosition(this); ContextMenu.Visibility = Visibility.Visible; ContextMenu.IsOpen = true; ContextMenu.SetValue(Canvas.LeftProperty, (double)p.X); ContextMenu.SetValue(Canvas.TopProperty, (double)p.Y); }
private void HideContextMenu() { ContextMenu.Visibility = Visibility.Collapsed; ContextMenu.IsOpen = false; } private void EnalbleEditForSelectedItem() { if (selectedNode != null) { SetTemplateForSelectedItem("TreeViewMainEditTemplate"); } }
private void DisableEditForSelectedItem() { if (selectedNode != null) { SetTemplateForSelectedItem("TreeViewMainReadTemplate");
selectedNode = null;
} }
private void SetTemplateForSelectedItem(String templateName) { HierarchicalDataTemplate hdt = (HierarchicalDataTemplate)Resources[templateName];
TreeViewItem selectedTreeViewItem =
TreeViewExtensions.GetContainerFromItem(TreeViewMain, selectedNode);
if (selectedTreeViewItem != null)
selectedTreeViewItem.HeaderTemplate = hdt; }
}
}
这样就完成了。
引用:
MichaelSnow : Silverlight Tip of the Day #3 – Mouse Right Clicks
MSDN : DataBinding Silverlight
Codeplex : Silverlight Toolkit
MSDN : INotifyPropertyChanged Interface
