在web开发中,带checkbox的tree是一个很有用的东东,比如权限选择、分类管理,如果不用sl,单纯用js+css实现是很复杂的,有了SL之后,就变得很轻松了
解决方案一:
利用Silvelright ToolKit(微软的开源项目),项目地址
http://silverlight.codeplex.com/
在线演示地址:http://silverlight.net/content/samples/sl4/toolkitcontrolsamples/run/default.html
解决方案二:
telerik公司的Rad for Silverlight商业控件(收费控件)
不管用哪一种方案,代码都是差不多的,为了实现数据绑定,先创建一个silverlight类库项目BusinessObject,定义数据项实体:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows.Markup; namespace BusinessObject { /// <summary> /// 地区数据项 /// </summary> [ContentProperty("Children")]//指示Children属性是 XAML 的Content内容属性 public class PlaceItem : INotifyPropertyChanged { /// <summary> /// 构造函数 /// </summary> public PlaceItem() { Children = new Collection<PlaceItem>(); IsSelected = true; } /// <summary> /// 地区名称 /// </summary> public string Name { get; set; } /// <summary> /// 地区描述 /// </summary> public string Description { get; set; } /// <summary> /// 得到下级元素容器 /// </summary> public Collection<PlaceItem> Children { get; private set; } /// <summary> /// 是否有子项 /// </summary> public bool HasChild { get { return Children.Count > 0; } } /// <summary> /// 是否选中 /// </summary> private bool? _isSelected; /// <summary> /// 该特性是否想要被安装 /// </summary> public bool? IsSelected { get { return _isSelected; } set { if (value != _isSelected) { _isSelected = value; OnPropertyChanged("IsSelected"); } } } public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// 属性改变时触发事件 /// </summary> /// <param name="propertyName">Property that changed.</param> private void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (null != handler) { handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } }
然后再定义一个 演示数据集合类:
using System.Collections.ObjectModel; using System.ComponentModel; using System.Windows.Markup; namespace BusinessObject { /// <summary> /// 地区数据项 /// </summary> [ContentProperty("Children")]//指示Children属性是 XAML 的Content内容属性 public class PlaceItem : INotifyPropertyChanged { /// <summary> /// 构造函数 /// </summary> public PlaceItem() { Children = new Collection<PlaceItem>(); IsSelected = true; } /// <summary> /// 地区名称 /// </summary> public string Name { get; set; } /// <summary> /// 地区描述 /// </summary> public string Description { get; set; } /// <summary> /// 得到下级元素容器 /// </summary> public Collection<PlaceItem> Children { get; private set; } /// <summary> /// 是否有子项 /// </summary> public bool HasChild { get { return Children.Count > 0; } } /// <summary> /// 是否选中 /// </summary> private bool? _isSelected; /// <summary> /// 该特性是否想要被安装 /// </summary> public bool? IsSelected { get { return _isSelected; } set { if (value != _isSelected) { _isSelected = value; OnPropertyChanged("IsSelected"); } } } public event PropertyChangedEventHandler PropertyChanged; /// <summary> /// 属性改变时触发事件 /// </summary> /// <param name="propertyName">Property that changed.</param> private void OnPropertyChanged(string propertyName) { PropertyChangedEventHandler handler = PropertyChanged; if (null != handler) { handler.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } } }
好了,开始干正事儿了:
toolkit中的treeview用法
xaml部分
<UserControl x:Class="ToolKit.MainPage" 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:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit" xmlns:local="clr-namespace:BusinessObject;assembly=BusinessObject" xmlns:common="clr-namespace:System.Windows;assembly=System.Windows.Controls"> <Grid x:Name="LayoutRoot" Background="White"> <Grid.Resources> <!--定义数据源--> <local:SampleData x:Key="SampleDataSource"></local:SampleData> <!--定义模板--> <common:HierarchicalDataTemplate x:Key="NodeTemplate" ItemsSource="{Binding Children}"> <StackPanel Orientation="Horizontal" ToolTipService.ToolTip="{Binding Description}"> <CheckBox IsTabStop="False" IsThreeState="{Binding HasChild}" IsChecked="{Binding IsSelected, Mode=TwoWay}" Click="ItemCheckbox_Click" /> <ContentPresenter Content="{Binding Name}" /> </StackPanel> </common:HierarchicalDataTemplate> </Grid.Resources> <sdk:TreeView Name="treeView1" ItemTemplate="{StaticResource NodeTemplate}" ItemsSource="{Binding Source={StaticResource SampleDataSource}, Path=SamplePlaceItemCollection}" Margin="10" BorderThickness="0"> <sdk:TreeView.ItemContainerStyle> <Style TargetType="sdk:TreeViewItem"> <!--默认全展开--> <Setter Property="IsExpanded" Value="True"/> </Style> </sdk:TreeView.ItemContainerStyle> </sdk:TreeView> </Grid> </UserControl>
后端cs部分:
using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using BusinessObject; namespace ToolKit { public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); this.Loaded += new RoutedEventHandler(MainPage_Loaded); } void MainPage_Loaded(object sender, RoutedEventArgs e) { this.treeView1.ItemsSource = SampleData.SamplePlaceItemCollection; this.treeView1.ExpandAll(); //var obj = this.treeView1.Items[1]; } /// <summary> /// 点击节点时,选中子节点,同时设置父节点状态 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void ItemCheckbox_Click(object sender, RoutedEventArgs e) { TreeViewItem item = GetParentTreeViewItem((DependencyObject)sender); if (item != null) { PlaceItem feature = item.DataContext as PlaceItem; if (feature != null) { UpdateChildrenCheckedState(feature); UpdateParentCheckedState(item); } } } /// <summary> /// 取得节点的父节点 /// </summary> /// <param name="item"></param> /// <returns></returns> private static TreeViewItem GetParentTreeViewItem(DependencyObject item) { if (item != null) { DependencyObject parent = VisualTreeHelper.GetParent(item); TreeViewItem parentTreeViewItem = parent as TreeViewItem; return (parentTreeViewItem != null) ? parentTreeViewItem : GetParentTreeViewItem(parent); } return null; } /// <summary> /// 更新父节点的选中状态 /// </summary> /// <param name="item"></param> private static void UpdateParentCheckedState(TreeViewItem item) { //取得父节点 TreeViewItem parent = GetParentTreeViewItem(item); if (parent != null) { PlaceItem parentItem = parent.DataContext as PlaceItem; if (parentItem != null) { bool? childrenCheckedState = parentItem.Children.First<PlaceItem>().IsSelected; for (int i = 1; i < parentItem.Children.Count(); i++) { if (childrenCheckedState != parentItem.Children[i].IsSelected) { childrenCheckedState = null; break; } } parentItem.IsSelected = childrenCheckedState; //递归处理上级父节点 UpdateParentCheckedState(parent); } } } /// <summary> /// 更新子节点选中状态 /// </summary> /// <param name="feature"></param> private static void UpdateChildrenCheckedState(PlaceItem feature) { if (feature.IsSelected.HasValue) { foreach (PlaceItem childFeature in feature.Children) { childFeature.IsSelected = feature.IsSelected; if (childFeature.Children.Count() > 0) { UpdateChildrenCheckedState(childFeature); } } } } } }
可以看到了,为了处理实现全选等功能,后端还是要写一些代码处理
telerik的treeview用法:
<UserControl x:Class="Telerik.MainPage" 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:common="clr-namespace:BusinessObject;assembly=BusinessObject" xmlns:telerik="http://schemas.telerik.com/2008/xaml/presentation"> <Grid x:Name="LayoutRoot" Background="White"> <Grid.Resources> <common:SampleData x:Key="SampleDataSource"></common:SampleData> <!--数据节点模板--> <DataTemplate x:Key="NodeTemplate"> <TextBlock Text="{Binding Name}" /> </DataTemplate> <!--子节点模板--> <telerik:HierarchicalDataTemplate x:Key="ChildTemplate" ItemTemplate="{StaticResource NodeTemplate}" ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Name}" /> </telerik:HierarchicalDataTemplate> <!--父节点模板--> <telerik:HierarchicalDataTemplate x:Key="ParentTemplate" ItemTemplate="{StaticResource ChildTemplate}" ItemsSource="{Binding Children}"> <TextBlock Text="{Binding Name}" /> </telerik:HierarchicalDataTemplate> </Grid.Resources> <telerik:RadTreeView ItemsSource="{Binding Source={StaticResource SampleDataSource}, Path=SamplePlaceItemCollection}" ItemTemplate="{StaticResource ParentTemplate}" SelectionMode="Extended" IsLineEnabled="True" ItemsOptionListType="CheckList" IsOptionElementsEnabled="True" IsRootLinesEnabled="True" IsTriStateMode="True" Margin="10"> <telerik:RadTreeView.ItemContainerStyle> <Style TargetType="telerik:RadTreeViewItem"> <!--默认全展开--> <Setter Property="IsExpanded" Value="True"/> </Style> </telerik:RadTreeView.ItemContainerStyle> </telerik:RadTreeView> </Grid> </UserControl>
后端代码:木有!--商业控件,就是靠谱,很多功能已经帮开发者实现了.
效果: