在开发Silverlight应用程序时,经常会遇到需要通过ViewModel来控制TreeView Control节点展开的情况。本文将介绍如何使用Behavior来实现这一功能,同时避免使用代码后台,以适应那些不具备编程能力的设计师使用Microsoft Expression Blend创建UI的需求。
首先,从TreeView Control的正常操作开始,使用ViewModel(MVVM模式)进行绑定。从一个简单的Category类开始,将Categories集合绑定到TreeView Control上。然后创建一个ICommand,用来设置节点的IsSelected属性。
        public ICommand SetCategoryCommand {
            get;
            set;
        }
        public void SetCategory(object param) {
            foreach (var Cat in colCategory) {
                var result = (from objCategory in Cat.AllChildren()
                              where objCategory.CategoryName == "Category Sub1-1"
                              select objCategory).FirstOrDefault();
                if (result != null) {
                    result.IsSelected = true;
                }
            }
        }
        private bool CanSetCategory(object param) {
            return true;
        }
    
然后,可以通过按钮来触发ICommand,从而选中节点上的复选框。但是,如果TreeView Control是折叠状态,即使节点被选中,也无法看到,除非手动展开TreeView节点。
为了解决这个问题,首先在ViewModel中创建一个属性来保存选中节点的值:
        private Category _SelectedCategory;
        public Category SelectedCategory {
            get {
                return _SelectedCategory;
            }
            set {
                if (SelectedCategory == value) {
                    return;
                }
                _SelectedCategory = value;
                this.NotifyPropertyChanged("SelectedCategory");
            }
        }
    
接下来,创建一个Behavior并将其放置在TreeView Control上。将按钮设置为触发Behavior,并将SelectedCategory绑定到Behavior上。注意,还有一个ExpandOnLoad复选框,允许指示节点是在页面加载时展开,还是通过事件(如按钮点击)触发。
当运行项目并点击按钮时,TreeView Control的节点将自动展开。Behavior的代码并不复杂,这是主要的工作方法:
        private void SelectNode() {
            if (SelectedCategory != null) {
                objTreeView.UpdateLayout();
                MainPageViewModel objMainPageViewModel = (MainPageViewModel)objTreeView.DataContext;
                ObservableCollection colCategories = (ObservableCollection)objMainPageViewModel.colCategory;
                foreach (var Cat in colCategories) {
                    var result = (from objCategory in Cat.AllChildren()
                                   where objCategory == SelectedCategory
                                   select objCategory).FirstOrDefault();
                    if (result != null) {
                        TreeViewItem objTreeViewItem = (TreeViewItem)objTreeView.ItemContainerGenerator.ContainerFromItem(Cat);
                        objTreeViewItem.IsExpanded = true;
                        objTreeView.UpdateLayout();
                        ExpandChildNode(objTreeViewItem, Cat);
                    }
                }
            }
        }
      
这个方法用于展开子节点:
        private void ExpandChildNode(TreeViewItem objTreeViewItem, Category Cat) {
            foreach (var item in Cat.Categories) {
                var result = (from objCategory in item.AllChildren()
                               where objCategory == SelectedCategory
                               select objCategory).FirstOrDefault();
                if (result != null) {
                    TreeViewItem SubTreeViewItem = (TreeViewItem)objTreeViewItem.ItemContainerGenerator.ContainerFromItem(item);
                    SubTreeViewItem.IsExpanded = true;
                    objTreeView.UpdateLayout();
                    ExpandChildNode(SubTreeViewItem, item);
                }
            }
        }