• 转:[Silverlight入门系列]使用MVVM模式(9): 想在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: xmlns:ei="clr-namespace:Microsoft.Expression.Interactivity.Core;assembly=Microsoft.Expression.Interactions"
       7: xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" 

      源代码下载

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

  • 相关阅读:
    标准C的标记化结构初始化语法
    STL中的lower_bound() 和 upper_bound()
    Linux中的file_operation结构
    Linux中进行模块操作的命令
    全球前50大名站
    jQuery实例——选项卡的实现
    我的RHCE之路——RedHat 6 破解grub 恢复grub方法
    PHP获取解析URL方法
    PHP笔试题——遍历文件目录
    PHP面试题——PHP字符串翻转函数
  • 原文地址:https://www.cnblogs.com/ookami/p/4480494.html
Copyright © 2020-2023  润新知