[译]Silverlight中TreeView增删改查和拖放
来自微软的Amit Dey提供了一个非常好的Sliverlight代码示例来展示了在Silverlight中树控件的增、删、改、查和拖放的功能。在Silverlight社区里面树控件的增、删、改、查是一个经常被问到的问题。但是我们收到还是有很多人请求得到这个代码示例。我们希望这个示例能够使开发人员轻松掌握这个典型的编程案例。
感谢Amit!
Silverlight TreeView控件的增删改查
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进行拖放。
<UserControl
xmlns: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
http://www.cnblogs.com/huazai/archive/2011/03/04/1970478.html
