http://blog.csdn.net/alsmile/article/details/6606673
刚开始接触的这个控件,有点不知道怎么用。网上看了下,好像大家都觉得不如winform里面的好使。反正,我以前是用mfc做界面的,对c#不熟。网上看了几个例子,自己动手做了一下,现在把大概步骤记录下来。我这里比较简单,没有用什么模式。网上有一篇《使用ViewModel模式来简化WPF的TreeView》大家可以看看。
一、一个简单的树
首先、定义一个树节点的类,用来保存树节点信息:
TreeItem.cs文件:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.ObjectModel; namespace WPFTreeviewExamples { class TreeItem { // 构造函数 public TreeItem() { children= new ObservableCollection<TreeItem>(); } ////////////////////////////////////////////////////////////////////////// // 节点文字信息 public stringtext { get; set; } // 节点其他信息 // ... // 父节点 public TreeItemparent { get; set; } // 子节点 public ObservableCollection<TreeItem> children { get; set; } ////////////////////////////////////////////////////////////////////////// } }
然后、在xaml文件中定义树的属性样式:
<TreeView Name="treeViewSimple" > <TreeView.ItemContainerStyle> <Style TargetType="{x:TypeTreeViewItem}"> <Setter Property="IsExpanded" Value="true"/> </Style> </TreeView.ItemContainerStyle> <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=children}"> <StackPanel Orientation="Horizontal" Margin="0,2,0,2"> <TextBlock Text="{Binding text}" ToolTip="{Binding text}"/> </StackPanel> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView>
其中:<Setter Property="IsExpanded" Value="true"/>表示所有节点都展开。
HierarchicalDataTemplate定义节点样式。DataType="{x:Typelocal:TreeItem}用来表明存储节点数据的类是什么。
二、带图标的树
很简单,只要添加图标相关信息即可:
TreeItem.cs文件:
////////////////////////////////////////////////////////////////////////// // 节点文字信息 public stringtext { get; set; } // 节点图标路径 public stringitemIcon { get; set; } // 节点其他信息 // ...
xaml文件
<TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=children}"> <StackPanel Orientation="Horizontal" Margin="0,2,0,2"> <Image VerticalAlignment="Center" Source="{Binding itemIcon}" ></Image> <TextBlock VerticalAlignment="Center" Text="{Binding text}" ToolTip="{Binding text}"/> </StackPanel> </HierarchicalDataTemplate> </TreeView.Resources>
三、更多功能的树
1、 首先,让我加一个checkbox
这需要完善 TreeItem:
让它继承与INotifyPropertyChanged 接口,以便通知checkbox状态改变:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Collections.ObjectModel; using System.ComponentModel; namespace WPFTreeviewExamples { class TreeItem: INotifyPropertyChanged { // 构造函数 public TreeItem() { children= new ObservableCollection<TreeItem>(); } ////////////////////////////////////////////////////////////////////////// // 节点文字信息 public stringtext { get; set; } // 节点图标路径 public stringitemIcon { get; set; } // 节点其他信息 // ... // 父节点 public TreeItemparent { get; set; } // 子节点 public ObservableCollection<TreeItem> children { get; set; } ////////////////////////////////////////////////////////////////////////// //////// Check 相关信息 /////////////////////////////////////////// bool? _isChecked= false; public bool?IsChecked { get{ return _isChecked;} set{ this.SetIsChecked(value, true, true); } } void SetIsChecked(bool? value, bool updateChildren,bool updateParent) { if(value == _isChecked) return; _isChecked= value; if(updateChildren && _isChecked.HasValue) { foreach(TreeItem childin children) { child.SetIsChecked(_isChecked,true, false); } } if(updateParent && parent != null) { parent.VerifyCheckState(); } this.OnPropertyChanged("IsChecked"); } void VerifyCheckState() { bool?state = null; for(int i = 0; i < this.children.Count;++i) { bool? current = this.children[i].IsChecked; if(i == 0) { state= current; } elseif (state !=current) { state= null; break; } } this.SetIsChecked(state,false, true); } //////////////////////////////////////////////////////////////////////////// void OnPropertyChanged(string prop) { if(this.PropertyChanged!= null) this.PropertyChanged(this,new PropertyChangedEventArgs(prop)); } public eventPropertyChangedEventHandler PropertyChanged; ////////////////////////////////////////////////////////////////////////// } }
<TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:TreeItem}" ItemsSource="{Binding Path=children}"> <StackPanel Orientation="Horizontal" Margin="0,2,0,2"> <CheckBox Focusable="False" IsChecked="{Binding IsChecked,Mode=TwoWay}"VerticalAlignment="Center" /> <Image VerticalAlignment="Center" Source="{Binding itemIcon}" ></Image> <TextBlock VerticalAlignment="Center" Text="{Binding text}" ToolTip="{Binding text}"/> </StackPanel> </HierarchicalDataTemplate> </TreeView.Resources>
void InitTree() { tree= new TreeItem(); // 添加一级顶层子节点 TreeItemroot = new TreeItem(); root.text = "根节点"; root.itemIcon = "./image/root.png"; // 把根节点加进来 tree.children.Add(root); root.parent = tree; // 给根节点加一些子节点 TreeItemhubei = new TreeItem(); hubei.text = "湖北"; hubei.itemIcon = "./image/Provine.png"; root.children.Add(hubei); hubei.parent = root; // 给湖北下加几个城市 TreeItemwuhan = new TreeItem(); wuhan.text = "武汉"; wuhan.itemIcon = "./image/City.png"; TreeItemxiaogan = newTreeItem(); xiaogan.text = "孝感"; xiaogan.itemIcon = "./image/City.png"; TreeItemxiangyang = newTreeItem(); xiangyang.text = "襄阳"; xiangyang.itemIcon = "./image/City.png"; hubei.children.Add(wuhan); wuhan.parent = hubei; hubei.children.Add(xiaogan); xiaogan.parent = hubei; hubei.children.Add(xiangyang); xiangyang.parent = hubei; // 给根节点加一些子节点 TreeItemfamily = newTreeItem(); family.text = "我的家"; family.itemIcon = "./image/Provine.png"; root.children.Add(family); family.parent = root; // 给湖北下加几个城市 TreeItemdad = new TreeItem(); dad.text = "爸爸"; dad.itemIcon = "./image/City.png"; TreeItemmom = new TreeItem(); mom.text = "妈妈"; mom.itemIcon = "./image/City.png"; TreeItemme = new TreeItem(); me.text = "我"; me.itemIcon = "./image/City.png"; TreeItembrother = newTreeItem(); brother.text = "弟弟"; brother.itemIcon = "./image/City.png"; family.children.Add(dad); dad.parent = family; family.children.Add(mom); mom.parent = family; family.children.Add(me); me.parent = family; family.children.Add(brother); brother.parent = family; // 把数据绑定到控件 treeViewMine.ItemsSource = tree.children; }
2、 tree的节点选择
在当前选择项(非checkbox)下加一个节点:
TreeItem selectItem = treeViewMine.SelectedItem as TreeItem; if(selectItem != null) { TreeItemnewItem = newTreeItem(); newItem.text = "这是一个新项"; newItem.itemIcon = "./image/City.png"; selectItem.children.Add(newItem); newItem.parent = selectItem; }
删除获得焦点的选择项:
TreeItem selectItem = treeViewMine.SelectedItem as TreeItem; selectItem.parent.children.Remove(selectItem);
删除checkbox选择的项
private void button1_Click(object sender, RoutedEventArgs e) { TreeDelChecked(tree); } bool TreeDelChecked(TreeItem item) { begin: foreach(TreeItem itemChildin item.children) { // 如果删除一个子节点后,foreach要重新遍历 if(TreeDelChecked(itemChild)) { gotobegin; } } if(item.IsChecked.HasValue) //check for avalue { if((bool)item.IsChecked && item.parent != null) //now this cast is safe { item.parent.children.Remove(item); returntrue; } } returnfalse; }
3、树右键选中和右键菜单
参考《在WPF的TreeView中实现右键选定》http://www.cnblogs.com/TianFang/archive/2010/02/10/1667153.html
<TreeView.ItemContainerStyle > <Style TargetType="{x:TypeTreeViewItem}" > <Setter Property="IsExpanded" Value="true"/> <EventSetter Event="TreeViewItem.PreviewMouseRightButtonDown" Handler="treeViewMine_PreviewMouseRightButtonDown"/> </Style> </TreeView.ItemContainerStyle>
private void treeViewMine_PreviewMouseRightButtonDown(object sender, MouseButtonEventArgs e) { TreeViewItemitem = VisualUpwardSearch<TreeViewItem>(e.OriginalSource as DependencyObject) asTreeViewItem; if(item != null) { item.ContextMenu = GetItemRightContextMenu(); item.Focus(); e.Handled = true; } } static DependencyObjectVisualUpwardSearch<T>(DependencyObjectsource) { while(source != null&& source.GetType()!= typeof(T)) source= VisualTreeHelper.GetParent(source); returnsource; } // 获得右键上下文菜单 ContextMenu GetItemRightContextMenu() { ContextMenumenu = new ContextMenu(); MenuItemmenuItem = newMenuItem(); menuItem.Header = "菜单"; menuItem.Click += new RoutedEventHandler(treeMenu_Click); menu.Items.Add(menuItem); returnmenu; } private voidtreeMenu_Click(objectsender, RoutedEventArgse) { if(MessageBox.Show("大家好,我是树的右键菜单事件!", "提示", MessageBoxButton.OKCancel,MessageBoxImage.Information)!= MessageBoxResult.OK) { return; } }