原贴地址:http://blog.csdn.net/qing2005/article/details/6523002
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ComponentModel;
using System.Collections.ObjectModel;
namespace DepartmentTreeView {
public class DepartmentViewModel:INotifyPropertyChanged {
//临时子节点用,当Expanded时移除此节点,添加子节点
static readonly DepartmentViewModel _temp = new DepartmentViewModel(null);
//选中的子节点
private static ObservableCollection<DepartmentViewModel> _checkedItems = new ObservableCollection<DepartmentViewModel>();
//根节点
static DepartmentViewModel _rootItem;
#region fields&properties
private bool? _isChecked;
public bool? IsChecked {
get { return _isChecked; }
set {
SetCheckState(value, true, true);
}
}
private void SetCheckState(bool? value, bool updateChildren, bool updateParent) {
if (_isChecked != value) {
_isChecked = value;
//通知选中项的集合
if (_isChecked == true) {
_checkedItems.Add(this);
PropertyChanged(this, new PropertyChangedEventArgs("CheckedItems"));
} else if (_isChecked == false) {
_checkedItems.Remove(this);
PropertyChanged(this, new PropertyChangedEventArgs("CheckedItems"));
}
PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
if (updateChildren) {
if (HasChildren()) {
Children.ForEach(c => c.SetCheckState(value, true, false));
}
}
if (updateParent && _parent != null) {
_parent.VerifyState();
}
}
}
private void VerifyState() {
bool? state = null;
for (int i = 0; i < this.Children.Count; ++i) {
bool? currentState = this.Children[i].IsChecked;
if (i == 0) {
state = currentState;
} else if (state != currentState) {
state = null;
break;
}
}
this.SetCheckState(state, false, true);
}
private bool _isExpanded;
public bool IsExpanded {
get { return _isExpanded; }
set {
if (value != _isExpanded) {
_isExpanded = value;
PropertyChanged(this, new PropertyChangedEventArgs("IsExpanded"));
}
if (!HasChildren()) {
Children.Remove(_temp);
LoadChildren();
}
}
}
private object _current;
public object Current {
get { return _current; }
set { _current = value; }
}
public string DisplayText {
get { return ((DepartmentTreeView.DB.SampleDataSet.DepartmentRow)Current)["DName"].ToString(); }
}
private DepartmentViewModel _parent;
public DepartmentViewModel Parent {
get { return _parent; }
set { _parent = value; }
}
private List<DepartmentViewModel> _children;
public List<DepartmentViewModel> Children {
get { return _children; }
private set { _children = value; }
}
#endregion
public static List<DepartmentViewModel> Create() {
var list = DepartmentHelper.GetSubDepartments(0);
DepartmentViewModel root = new DepartmentViewModel(null);
_rootItem = root;
root.Children.Clear();
foreach (var item in list) {
root.Children.Add(new DepartmentViewModel(item));
}
return root.Children;
}
private DepartmentViewModel(object currentObject) {
Current = currentObject;
_isChecked = false;
Children = new List<DepartmentViewModel>();
Children.Add(_temp);
}
/// <summary>
/// 初始化,用于设置父节点
/// </summary>
private void Init() {
if (!HasChildren()) return;
foreach (DepartmentViewModel child in Children) {
child.Parent = this;
child.Init();
}
PropertyChanged(this, new PropertyChangedEventArgs("Children"));
}
/// <summary>
/// 加载子节点
/// </summary>
private void LoadChildren() {
if (Current != null) {
int pid = Convert.ToInt32(((DepartmentTreeView.DB.SampleDataSet.DepartmentRow)Current)["DID"]);
var list = DepartmentHelper.GetSubDepartments(pid);
foreach (var item in list) {
DepartmentViewModel model = new DepartmentViewModel(item) { _isChecked = this.IsChecked };
if (model.IsChecked == true) {
_checkedItems.Add(model);
PropertyChanged(this, new PropertyChangedEventArgs("CheckedItems"));
}
Children.Add(model);
}
Init();
}
}
/// <summary>
/// 判断是否有子节点(逻辑是:如果只有一个临时子节点,说明没有真正的子节点)
/// </summary>
/// <returns></returns>
private bool HasChildren() {
return !(Children.Count == 1 && Children[0] == _temp);
}
public ObservableCollection<DepartmentViewModel> CheckedItems {
get {
return _checkedItems;
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
}
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Data;
using System.Windows.Documents;
using System.ComponentModel;
namespace DepartmentTreeView {
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window {
public MainWindow() {
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e) {
ObjectDataProvider provider = FindResource("depProvider") as ObjectDataProvider;
List<DepartmentViewModel> firstLevelItems = provider.Data as List<DepartmentViewModel>;
ICollectionView view = CollectionViewSource.GetDefaultView(firstLevelItems);
DepartmentViewModel rootItem = view.CurrentItem as DepartmentViewModel;
List<DepartmentViewModel> checkedItems = CollectionViewSource.GetDefaultView(provider) as List<DepartmentViewModel>;
StringBuilder builder = new StringBuilder();
foreach (DepartmentViewModel checkItem in rootItem.CheckedItems) {
builder.AppendLine(checkItem.DisplayText);
}
MessageBox.Show("Checked items:/n" + builder.ToString());
}
}
}
<Window x:Class="DepartmentTreeView.MainWindow"
xmlns=""
xmlns:x=""
xmlns:local="clr-namespace:DepartmentTreeView"
Title="MainWindow" Height="329" Width="212" FontFamily="Arial">
<Window.Resources>
<ObjectDataProvider x:Key="depProvider" ObjectType="{x:Type local:DepartmentViewModel}" MethodName="Create" />
<Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
<Setter Property="IsExpanded" Value="{Binding Path=IsExpanded,Mode=TwoWay}" />
</Style>
<HierarchicalDataTemplate x:Key="CheckBoxItemTemplate" ItemsSource="{Binding Children}">
<StackPanel Orientation="Horizontal" Margin="0,2,0,0">
<CheckBox Focusable="False" IsChecked="{Binding IsChecked,Mode=TwoWay}" VerticalAlignment="Center" />
<ContentPresenter Content="{Binding DisplayText,Mode=OneWay}" Margin="2,0" />
</StackPanel>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid Margin="5">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TreeView Name="tvDepartment" Grid.Row="0" ItemContainerStyle="{StaticResource TreeViewItemStyle}" ItemsSource="{Binding Source={StaticResource depProvider}}" ItemTemplate="{StaticResource CheckBoxItemTemplate}" />
<TextBlock Name="tbText" Margin="5" Grid.Row="1">当前选中项:<TextBlock Text="{Binding Source={StaticResource depProvider},Path=CheckedItems.Count,Mode=OneWay,IsAsync=True}" /></TextBlock>
<Button Margin="5" Grid.Row="2" Content="Get CheckedItems" Click="Button_Click" />
</Grid>
</Window>