且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

WPF MVVM实现TreeView

更新时间:2022-09-16 20:13:00

今天有点时间,做个小例子WPF MVVM 实现TreeView 只是一个思路大家可以***扩展

文章最后给出了源码下载地址

图1WPF MVVM实现TreeView   图2     WPF MVVM实现TreeView

模版加上了一个checkbox,选中父类的checkbox 所有的子类也相就选中。

如果子类没有全部父类的checkbox不会选中

用vmmm我们要先实现INotifyPropertyChanged

/// <summary>
///
/// </summary>
public class NotifyPropertyBase : INotifyPropertyChanged
{
    #region INotifyPropertyChanged
    public void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    public event PropertyChangedEventHandler PropertyChanged;
    #endregion
}

为了避免硬编码错误我写一个扩展方法

/// <summary>
  /// 扩展方法
  /// 避免硬编码问题
  /// </summary>
  public static class NotifyPropertyBaseEx
  {
      public static void SetProperty<T, U>(this T tvm, Expression<Func<T, U>> expre) where T : NotifyPropertyBase, new()
      {
          string _pro = CommonFun.GetPropertyName(expre);
          tvm.OnPropertyChanged(_pro);
      }
  }
  #endregion
 
 
  public class CommonFun
  {
      /// <summary>
      /// 返回属性名
      /// </summary>
      /// <typeparam name="T"></typeparam>
      /// <typeparam name="U"></typeparam>
      /// <param name="expr"></param>
      /// <returns></returns>
      public static string GetPropertyName<T, U>(Expression<Func<T, U>> expr)
      {
          string _propertyName = "";
          if (expr.Body is MemberExpression)
          {
              _propertyName = (expr.Body as MemberExpression).Member.Name;
          }
          else if (expr.Body is UnaryExpression)
          {
              _propertyName = ((expr.Body as UnaryExpression).Operand as MemberExpression).Member.Name;
          }
          return _propertyName;
      }
  }

下面我们就来实现treeveivew的绑定类

/// <summary>
   /// 因为用到泛型了不能写成abstract 类
   ///
   /// </summary>
   public  class MyTree : NotifyPropertyBase
   {
 
 
       #region 父
       public MyTree Parent
       {
           get;
           set;
       }
       #endregion
 
       #region 子
       public List<MyTree> Children
       {
           get;
           set;
       }
       #endregion
 
       #region 节点的名字
       public string Name
       {
           get;
           set;
       }
       #endregion
 
       #region Constructors
       public MyTree(string name)
       {
           this.Name=name;
           this.Children=new List<MyTree>();
       }
       public MyTree() { }
 
       public
       #endregion
 
       #region CheckBox是否选中
       bool? _isChecked;
       public bool? IsChecked
       {
           get
           {
               return _isChecked;
           }
           set
           {
               SetIsChecked(value, true, true);
           }
       }
 
       private void SetIsChecked(bool? value, bool checkedChildren, bool checkedParent)
       {
           if (_isChecked == value) return;
           _isChecked = value;
           //选中和取消子类
           if (checkedChildren && value.HasValue && Children != null)
               Children.ForEach(ch => ch.SetIsChecked(value, true, false));
 
           //选中和取消父类
           if (checkedParent && this.Parent != null)
               this.Parent.CheckParentCheckState();
 
           //通知更改
            
           this.SetProperty(x => x.IsChecked);
       }
 
       /// <summary>
       /// 检查父类是否选 中
       /// 如果父类的子类中有一个和第一个子类的状态不一样父类ischecked为null
       /// </summary>
       private void CheckParentCheckState()
       {
           bool? _currentState = this.IsChecked;
           bool? _firstState = null;
           for (int i = 0; i < this.Children.Count(); i++)
           {
               bool? childrenState = this.Children[i].IsChecked;
               if (i == 0)
               {
                   _firstState = childrenState;
               }
               else if (_firstState != childrenState)
               {
                   _firstState = null;
               }
           }
           if (_firstState != null) _currentState = _firstState;
           SetIsChecked(_firstState, false, true);
       }
 
       #endregion
 
       #region 选中的行 IsSelected
       bool _isSelected;
       public bool IsSelected
       {
           get
           {
               return _isSelected;
           }
           set
           {
               _isSelected = value;
               this.SetProperty(x => x.IsChecked);
               if (_isSelected)
               {
                   SelectedTreeItem = this;
                   MessageBox.Show("选中的是" + SelectedTreeItem.Name);
               }
               else
                   SelectedTreeItem = null;
           }
       }
       #endregion
 
       #region 选中的数据
       public MyTree SelectedTreeItem
       {
           get;
           set;
       }
       #endregion
 
       #region 创建树
 
       public void CreateTreeWithChildre( MyTree children,bool? isChecked)
       {
           this.Children.Add(children);
 
           children.Parent = this;
           children.IsChecked = isChecked;
       }
       #endregion
   }

 

我们再下面实现ViewModel

public class TreeViewModel:NotifyPropertyBase
   {
       public List<MyTree> MyTrees
       {
           get;
           set;
       }
       public TreeViewModel()
       {
           MyTrees = new List<MyTree>();
           MyTrees.Add(MyCreateTree());
            
       }
       /// <summary>
       /// 创建树
       /// </summary>
       /// <returns></returns>
       public MyTree MyCreateTree()
       {
           MyTree _myT = new MyTree("中国");
           #region 北京
           MyTree _myBJ = new MyTree("北京");
           _myT.CreateTreeWithChildre(_myBJ, false);
           MyTree _HD = new MyTree("海淀区");
            
            
           MyTree _CY = new MyTree("朝阳区");
           MyTree _FT = new MyTree("丰台区");
           MyTree _DC = new MyTree("东城区");
 
           _myBJ.CreateTreeWithChildre(_HD, false);
           _HD.CreateTreeWithChildre(new MyTree("某某1"), false);
           _HD.CreateTreeWithChildre(new MyTree("某某2"), true);
           _myBJ.CreateTreeWithChildre(_CY, false);
           _myBJ.CreateTreeWithChildre(_FT, false);
           _myBJ.CreateTreeWithChildre(_DC, false);
 
           #endregion
 
           #region 河北
           MyTree _myHB = new MyTree("河北");
           _myT.CreateTreeWithChildre(_myHB, false);
           MyTree _mySJZ = new MyTree("石家庄");
           MyTree _mySD = new MyTree("山东");
         
           MyTree _myTS = new MyTree("唐山");
 
           _myHB.CreateTreeWithChildre(_mySJZ, true);
           _myHB.CreateTreeWithChildre(_mySD, false);
           _myHB.CreateTreeWithChildre(_myTS, false);
           #endregion
 
           return _myT;
       }
 
        
   }

  

我们再实现一个TreeView的模版

WPF MVVM实现TreeView
<Window x:Class="MyWpfCheckTreeDemo.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:VM="clr-namespace:MyWpfCheckTreeDemo.AppViewModel"
        Title="MainWindow" Height="350" Width="525" Loaded="LoadedEvent">
    <Window.Resources>
        <HierarchicalDataTemplate x:Key="MyTreeItemTemplate"  DataType="{x:Type VM:MyTree}" ItemsSource="{Binding Path=Children,Mode=OneWay}">
            <StackPanel x:Name="My_SP"  Orientation="Horizontal" Margin="2">
                <CheckBox  IsChecked="{Binding Path=IsChecked}" >
                </CheckBox>
                <ContentPresenter  Content="{Binding Path=Name,Mode=OneTime}" Margin="2,0"/>
            </StackPanel>
        </HierarchicalDataTemplate>
        <Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
            <Setter Property="IsExpanded" Value="True" />
            <Setter Property="IsSelected" Value="{Binding Path=IsSelected,Mode=TwoWay}"/>
        </Style>
    </Window.Resources>
    <Grid>
        <DockPanel>
            
            <TreeView  x:Name="tv" ItemsSource="{Binding MyTrees}"
                      ItemContainerStyle="{StaticResource TreeViewItemStyle}"
                      ItemTemplate="{StaticResource MyTreeItemTemplate}"
                      ></TreeView>
        </DockPanel>
        
    </Grid>
</Window> 
WPF MVVM实现TreeView

 

 源码地址:MyWpfCheckTreeDemo.rar

 本文转自lpxxn博客园博客,原文链接:http://www.cnblogs.com/li-peng/p/3152982.html,如需转载请自行联系原作者