使用 ViewModel (MVVM) 以编程方式扩展 Silverlight Tree View 控件节点






4.98/5 (18投票s)
使用 ViewModel (MVVM) 以编程方式选择 Silverlight Tree View 控件节点。

Silverlight 树形视图控件和视图模型 (MVVM)
实时示例: http://silverlight.adefwebserver.com/ViewModelTreeControl
另请参阅: Silverlight DataTrigger 是解决视图模型/MVVM 问题的答案
当使用 Silverlight 树形视图控件时,您会发现如果没有使用代码隐藏,则程序化展开树节点并不容易。本文展示了如何使用 行为来实现这一点。
使用 Silverlight 树形视图控件
让我们看一下使用 视图模型 (MVVM) 的 Silverlight 树形视图控件的正常操作

我们从一个简单的 Category(类别)类开始...

我们将 Categories(类别)的集合绑定到 树形视图控件。
我们创建一个 ICommand,它将设置其中一个节点的 IsSelected 属性
public ICommand SetCategoryCommand { get; set; }
public void SetCategory(object param)
{
foreach (var Cat in colCategory)
{
// Find the Node
var result = (from objCategory in Cat.AllChildren()
where objCategory.CategoryName == "Category Sub1-1"
select objCategory).FirstOrDefault();
if (result != null)
{
// Set the IsSelected property so the checkbox
// will be checked
result.IsSelected = true;
}
}
}
private bool CanSetCategory(object param)
{
return true;
}
然后,我们可以使用 Button(按钮)调用 ICommand,并选中节点上的复选框。

问题是,如果 Silverlight 树形视图控件处于折叠状态,则 Node(节点)将被选中,但除非您展开树 Node(节点),否则您不会知道它。
程序化地选择树节点
程序化地选择 Tree Node(树节点)的第一步是在 View Model(视图模型)中创建一个属性以保存所选节点的值
private Category _SelectedCategory;
public Category SelectedCategory
{
get { return _SelectedCategory; }
set
{
if (SelectedCategory == value)
{
return;
}
_SelectedCategory = value;
this.NotifyPropertyChanged("SelectedCategory");
}
}
并设置值
// Set the SelectedCategory property
// so the Behavior will know what node to open
SelectedCategory = objCategorySub0;
接下来,我们创建一个 Behavior(行为)并将其放置在 Tree View Control(树形视图控件)上。

我们将 Button(按钮)设置为触发 Behavior(行为),并将 SelectedCategory(选定类别)绑定到 Behavior(行为)。
请注意,还有一个 ExpandOnLoad(加载时展开)复选框,允许我们指示节点是在页面加载时展开,还是在触发事件(例如 Button(按钮)点击)时展开。

当我们运行项目并单击 Button(按钮)时...

Silverlight 树形视图控件节点将自动展开。
行为
Behavior(行为)不包含很多代码。 这是完成大部分工作的方法
private void SelectNode()
{
// Only try to expand Node if the SelectedCategory is set
if (SelectedCategory != null)
{
// Refresh Tree Control
objTreeView.UpdateLayout();
// Get the DataContext of the Tree Control
MainPageViewModel objMainPageViewModel =
(MainPageViewModel)objTreeView.DataContext;
// Get collection of items bound to Tree Control
ObservableCollection<category> colCategories =
(ObservableCollection<category>)objMainPageViewModel.colCategory;
// Loop through the top levels items
foreach (var Cat in colCategories)
{
// Find the Node - Is it a child of this parent?
var result = (from objCategory in Cat.AllChildren()
where objCategory == SelectedCategory
select objCategory).FirstOrDefault();
// If the selected item is a child of the Parent
if (result != null)
{
// Get the Tree Control node container for the item
TreeViewItem objTreeViewItem =
(TreeViewItem)objTreeView.ItemContainerGenerator.ContainerFromItem(Cat);
// Expand the Node
objTreeViewItem.IsExpanded = true;
// Refresh Tree Control
objTreeView.UpdateLayout();
ExpandChildNode(objTreeViewItem, Cat);
}
}
}
}
// This method expands child nodes
private void ExpandChildNode(TreeViewItem objTreeViewItem, Category Cat)
{
// Loop through all the sub Categories
foreach (var item in Cat.Categories)
{
// Find the Node - Is it a child of this parent?
var result = (from objCategory in item.AllChildren()
where objCategory == SelectedCategory
select objCategory).FirstOrDefault();
// If the selected item is a child of the Parent
if (result != null)
{
// Get the Tree Control node container for the item
TreeViewItem SubTreeViewItem = (TreeViewItem)
objTreeViewItem.ItemContainerGenerator.ContainerFromItem(item);
// Expand the Node
SubTreeViewItem.IsExpanded = true;
// Refresh Tree Control
objTreeView.UpdateLayout();
// Recursively call the function
ExpandChildNode(SubTreeViewItem, item);
}
}
}
代码隐藏有什么问题?
我正在处理一些项目,我们允许 Designer(设计师)(没有编程能力)使用 Microsoft Expression Blend 为 Silverlight 应用程序创建 UI。 因此,我们不想使用任何代码隐藏,因为 Designer(设计师)需要知道如何编程以避免破坏某些东西。
当我们能够实现没有代码隐藏的 Silverlight 项目时,我们不会遇到这个问题。