[译]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
