更新时间:2022-09-16 20:13:00
今天有点时间,做个小例子WPF MVVM 实现TreeView 只是一个思路大家可以***扩展
文章最后给出了源码下载地址
图1 图2
模版加上了一个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的模版
<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>
本文转自lpxxn博客园博客,原文链接:http://www.cnblogs.com/li-peng/p/3152982.html,如需转载请自行联系原作者