你的位置:首页 > ASP.net教程

[ASP.net教程]转:[Silverlight入门系列]使用MVVM模式: 想在ViewModel中控制TreeView节点展开?


很多童鞋看了我的博客以后也去实践MVVM,但却发现Silverlight实践中的MVVM很难实现,比纯粹的CodeBehind难度大很多。首先是原来在xaml.cs的CodeBehind部分很容易控制界面逻辑,现在这部分逻辑移到ViewModel里面去了以后,就很难调用CodeBind的部分;其次是很多View和ViewModel、或者一个ViewModel多个View,他们之间如何通

  

  很多童鞋看了我的博客以后也去实践MVVM,但却发现Silverlight实践中的MVVM很难实现,比纯粹的CodeBehind难度大很多。首先是原来在xaml.cs的CodeBehind部分很容易控制界面逻辑,现在这部分逻辑移到ViewModel里面去了以后,就很难调用CodeBind的部分;其次是很多View和ViewModel、或者一个ViewModel多个View,他们之间如何通信?这些问题貌似非常复杂。其实很简单,就是分割、分工、协同。搞清楚谁应该负责什么,如何抽象和隔离、然后如何用适合的技术来实现。这些问题想清楚了搞清楚了就不难了。

  提出问题:MVVM的TreeView不能在ViewModel中按需展开TreeNode节点

  今天要讲的就是一个很常见的问题:你的TreeView已经用MVVM模式实现了(参见这一篇:[Silverlight入门系列]Prism中TreeView真正实现MVVM模式和Expanded发生时异步动态加载子节点(WCFRiaService)),但你在ViewModel的业务逻辑加载了节点以后要自动展开第一个节点怎么办?你发现现在不能直接调用Node.Expand()方法了,因为你在ViewModel中。怎么办?本文的方法其实很简单,也是Silverlight中MVVM消除CodeBehind的万能膏药:DataTrigger + Behavior。(其它方法参见我的上一篇:[Silverlight入门系列]使用MVVM模式(9): 想在ViewModel中控制Storyboard动画?)

  解决思路:Silverlight中MVVM消除CodeBehind的万能膏药:DataTrigger + Behavior

  首先实现一个Behavior,这个行为就是展开TreeView的Root节点喽。然后这个Behavior什么时候执行呢?我们需要是按需执行。呼叫它的时候它才执行。那就在ViewModel里面加一个属性,这个属性实现了INotifyPropertyChanged接口,当ViewModel里面一段逻辑执行完毕需要呼叫它展开节点了,那就设置这个属性为True,它就会因为绑定自动通知界面。而Behavior和这个属性怎么联系起来?那就是通过Trigger,监控这个属性变化,当值变为需要的值就自动执行你的Behavior。思路就是这样。

  实现代码

  

09.20

 

  上面那个图是最后的XAML代码了。先来看看展开根节点的Behavior: 

  1: using System.Windows.Controls;
  2: using System.Windows.Interactivity;
  3: using System.ComponentModel;
  4: using System;
  5:  
  6: namespace SilverlightApplication1
  7: {
  8:   [System.ComponentModel.Description("Expands Tree Root Node")]
  9:   public class TreeRootExpandBehavior : TargetedTriggerAction<LazyTreeView>, INotifyPropertyChanged
 10:   {
 11:     #region "Initialization"
 12:  
 13:     private LazyTreeView objTreeView;
 14:  
 15:     /// <summary>
 16:     /// Called after the action is attached to an AssociatedObject.
 17:     /// </summary>
 18:     protected override void OnAttached()
 19:     {
 20:       base.OnAttached();
 21:  
 22:       objTreeView = (LazyTreeView)(AssociatedObject);
 23:     }
 24:  
 25:     /// <summary>
 26:     /// Invokes the action.
 27:     /// </summary>
 28:     /// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
 29:     protected override void Invoke(object parameter)
 30:     {
 31:       ExpandRoot();
 32:     }
 33:  
 34:     #endregion
 35:  
 36:     #region "Expands the root"
 37:  
 38:     /// <summary>
 39:     /// Expands the root.
 40:     /// </summary>
 41:     private void ExpandRoot()
 42:     {
 43:       objTreeView.UpdateLayout();
 44:  
 45:       var vm = (MyViewModel)objTreeView.DataContext; //MyViewModel是你的TreeView的ViewModel
 46:       if (vm == null) return;
 47:  
 48:       var root = vm.Root;//这个是ViewModel的一个公共属性,你的可能不一样,知道原理就行了
 49:       if (vm.Root == null || vm.Root.Count == 0) return;
 50:  
 51:       var objTreeViewItem = (TreeViewItem)objTreeView.ItemContainerGenerator.ContainerFromItem(root[0]);
 52:       if (objTreeViewItem != null)
 53:       {
 54:         objTreeViewItem.IsExpanded = true;
 55:         objTreeView.UpdateLayout();
 56:       }
 57:     }
 58:  
 59:     #endregion
 60:  
 61:     #region "INotifyPropertyChanged Implementation"
 62:  
 63:     public event PropertyChangedEventHandler PropertyChanged;
 64:  
 65:     /// <summary>
 66:     /// Notifies the property changed.
 67:     /// </summary>
 68:     /// <param name="info">The info.</param>
 69:     private void NotifyPropertyChanged(String info)
 70:     {
 71:       if (PropertyChanged != null)
 72:       {
 73:         PropertyChanged(this, new PropertyChangedEventArgs(info));
 74:       }
 75:     }
 76:     #endregion
 77:   }
 78: }




 

  在ViewModel里面加个属性

  

09.201

 

  当ViewModel里面一段逻辑执行完毕需要呼叫它展开节点了,那就设置这个属性为True,它就会因为绑定自动通知界面。而Behavior和这个属性怎么联系起来?那就是通过Trigger,监控这个属性变化,当值变为需要的值就自动执行你的Behavior。注意引用几个命名空间:

  1: //引用下面命名空间:
  2: System.Windows.Interactivity
  3: Microsoft.Expression.Interactions
  4:  
  5: //在Xaml中:
  6: 
  7: 


  源代码下载

  本文来自Mainz的博客,原文地址:http://www.cnblogs.com/Mainz/archive/2011/09/20/2182267.html