今天有点时间,做个小例子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,如需转载请自行联系原作者