天涯一飘絮

导航

 
二、带复选框的TreeView

说明:在TreeView中设置复选框是十分常见的,这有助于我们对于同组数据的一次性选取或取消。本文就将为你介绍怎样在Silverlight中实现带有Checkbox的TreeView。

 

最初的步骤

ObjectCollection

这是Silverlight Toolkit 提供的一个对象集合,用以提供静态的对象资源绑定。注意:使用时一定要添加System.Windows.Controls.Toolkit的引用。在Skysigal上有一篇介绍静态资源数据绑定的好文章[链接],推荐给大家。

HierarchicalDataTemplate

这是用于处理层次状数据而设置的数据模板,其主要用于具有HeaderedItemsControl的组件,比如说TreeViewItem。详细内容请参考这里

INotifyPropertyChanged

向客户端发出某一属性值已更改的通知。主要用于实现数据的双向绑定。详细内容请参考这里

 

实现业务对象Feature

通过实现该业务对象,将能使其与TreeView进行交互。构建起这一对象的步骤主要有下述几步:

第一,声明可在XAML文件中显示的内容属性,添加属性标签[ContentProperty("SubComponents")]。

第二,使Feature对象继承接口INotifyPropertyChanged。

第三,设定Feature对象的属性。

第四,添加实现Checkbox效果的重要属性HasSubcomponents和ShouldInstall。

第五,实现接口INotifyPropertyChanged定义的函数。

具体代码请见下文。

 

具体部署组件

在MainPage.xaml文件中添加Feature对象的ObjectCollection资源,添加代表Feature对象Item的模板,以及添加有关数据对象的资源绑定。在MainPage.xaml.cs文件中添加对于TreeView组件的事件处理函数。具体代码请见下文。

 


实例

效果图




代码段

Feature业务对象代码(Feature.cs)

using System.Collections.ObjectModel;

using System.ComponentModel;

using System.Windows.Markup;

 

namespace SilverlightClient

{

    [ContentProperty("Subcomponents")] //声明可在XAML文件中显示的内容属性

    public class Feature : INotifyPropertyChanged //继承接口INotifyPropertyChanged用于双向数据绑定

    {

        //Feature对象的属性

        public string FeatureName { get; set; }

        public string Description { get; set; }

 

        //声明全局变量

        public Collection<Feature> Subcomponents { get; private set; }

        private bool? _shouldInstall;

 

        //是否有子组件

        public bool HasSubcomponents

        {

            get

            {

                return Subcomponents.Count > 0;

            }

        }

       

        //是否允许Feature进行安置

        public bool? ShouldInstall

        {

            get

            {

                return _shouldInstall;

            }

            set

            {

                if (value != _shouldInstall)

                {

                    _shouldInstall = value;

                    OnPropertyChanged("ShouldInstall");

                }

            }

        }

 

        //构造函数

        public Feature()

        {

            Subcomponents = new Collection<Feature>();

            ShouldInstall = true;

        }

 

        //事件委托

        public event PropertyChangedEventHandler PropertyChanged;

 

        //实现接口INotifyPropertyChanged定义函数

        private void OnPropertyChanged(string propertyName)

        {

            PropertyChangedEventHandler handler = PropertyChanged;

            if (null != handler)

            {

                handler.Invoke(this, new PropertyChangedEventArgs(propertyName));

            }

        }

    }

}

MainPage.xaml代码

<UserControl

    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"

    xmlns:toolkit="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Toolkit"

    xmlns:controls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls"

    xmlns:common="clr-namespace:System.Windows;assembly=System.Windows.Controls"

    xmlns:samplesCommon="clr-namespace:SilverlightClient"

    mc:Ignorable="d" x:Class="SilverlightClient.MainPage"

    Width="640" Height="480">

 <Grid x:Name="LayoutRoot" Background="White" Width="640" Height="480">

        <StackPanel>

            <StackPanel.Resources>

                <!-- 用于安置的示例Features -->

                <toolkit:ObjectCollection x:Key="CorporationFeatures">

                    <samplesCommon:Feature FeatureName="公司部门" Description="公司各部门的结构">

                        <samplesCommon:Feature FeatureName="建筑部" Description="负责公司的工程项目">

                            <samplesCommon:Feature FeatureName="设计科" Description="负责项目的设计" />

                            <samplesCommon:Feature FeatureName="工程科" Description="负责项目的具体实施" />

                        </samplesCommon:Feature>

                        <samplesCommon:Feature FeatureName="管理部" Description="负责管理公司的财务与人事">

                            <samplesCommon:Feature FeatureName="财务科" Description="负责公司的对内对外的财务事宜" />

                            <samplesCommon:Feature FeatureName="总务人事科" Description="负责公司日常事务及员工招聘" />

                        </samplesCommon:Feature>

                    </samplesCommon:Feature>

                </toolkit:ObjectCollection>

 

                <!-- 代表一个Feature项的模板 -->

                <common:HierarchicalDataTemplate x:Key="NodeTemplate" ItemsSource="{Binding Subcomponents}">

                    <StackPanel Orientation="Horizontal" ToolTipService.ToolTip="{Binding Description}">

                        <CheckBox

                        IsTabStop="False"                       

                        IsThreeState="{Binding HasSubcomponents}"

                        IsChecked="{Binding ShouldInstall, Mode=TwoWay}"

                        Click="ItemCheckbox_Click"

                        />

                        <ContentPresenter Content="{Binding FeatureName}" />

                    </StackPanel>

                </common:HierarchicalDataTemplate>

            </StackPanel.Resources>

 

            <Grid>

                <Grid.ColumnDefinitions>

                    <ColumnDefinition Width="*" />

                    <ColumnDefinition Width="2*" />

                </Grid.ColumnDefinitions>

 

                <controls:TreeView

                Grid.Column="0"               

                ItemTemplate="{StaticResource NodeTemplate}"

                ItemsSource="{StaticResource CorporationFeatures}" FontSize="14">

 

                    <!-- 用来一次展开TreeView所有结点 -->

                    <controls:TreeView.ItemContainerStyle>

                        <Style TargetType="controls:TreeViewItem">

                            <Setter Property="IsExpanded" Value="True" />

                        </Style>

                    </controls:TreeView.ItemContainerStyle>

                </controls:TreeView>

               

            </Grid>

        </StackPanel>

    </Grid>

</UserControl>

MainPage.xaml.cs代码

using System;

using System.Collections.Generic;

using System.Linq;

using System.Net;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Animation;

using System.Windows.Shapes;

 

namespace SilverlightClient

{

    public partial class MainPage : UserControl

    {

        public MainPage()

        {

            InitializeComponent();

        }

 

        //处理Checkbox点击事件

        private void ItemCheckbox_Click(object sender, RoutedEventArgs e)

        {

            TreeViewItem item = GetParentTreeViewItem((DependencyObject)sender);

            if (item != null)

            {

                Feature feature = item.DataContext as Feature;

                if (feature != null)

                {

                    UpdateChildrenCheckedState(feature);//更新子组件选中状态

                    UpdateParentCheckedState(item);//更新父组件选中状态

                }

            }

        }

       

        //静态方法:获取父级TreeViewItem

        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);//如果父级TreeViewItem存在则返回,否则就递归寻找

            }

            //找不到父对象,返回父对象不存在

            return null;

        }

       

        //静态方法:更新父级TreeViewItem选中状态

        private static void UpdateParentCheckedState(TreeViewItem item)

        {

            TreeViewItem parent = GetParentTreeViewItem(item);//获取父级TreeViewItem

            if (parent != null)//如果父对象不为空,为空则退出递归寻找

            {

                Feature feature = parent.DataContext as Feature;//对象转换

                if (feature != null)//如果对象不为空

                {

                    //更新子组件的选中状态

                    bool? childrenCheckedState = feature.Subcomponents.First<Feature>().ShouldInstall;//得到第一个子组件的选中状态

                    for (int i = 1; i < feature.Subcomponents.Count(); i++)

                    {

                        if (childrenCheckedState != feature.Subcomponents[i].ShouldInstall)

                        {

                            childrenCheckedState = null;

                            break;

                        }

                    }

 

                    //将父组件的选中状态与子组件置为相同

                    feature.ShouldInstall = childrenCheckedState;

 

                    //继续递归搜索.

                    UpdateParentCheckedState(parent);

                }

            }

        }

 

        //用递归更新子组件的选中状态

        private static void UpdateChildrenCheckedState(Feature feature)

        {

            if (feature.ShouldInstall.HasValue)

            {

                foreach (Feature childFeature in feature.Subcomponents)

                {

                    childFeature.ShouldInstall = feature.ShouldInstall;

                    if (childFeature.Subcomponents.Count() > 0)

                    {

                        UpdateChildrenCheckedState(childFeature);

                    }

                }

            }

        }

 

   }

posted on 2009-08-28 22:18  冰云  阅读(366)  评论(0编辑  收藏  举报