using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using FWindSoft.Wpf;
namespace FWindSoft.Wpf.Controls
{
///
/// TreeCategory.xaml 的交互逻辑
///
public partial class TreeCategory : UserControl
{
public TreeCategory()
{
InitializeComponent();
}
}
public partial class TreeCategory
{
/*
* 绑定数据源必须存在Name的属性
* 直接和界面中属性关联的 使用绑定进行关联
* 如果公开的属性和界面中用到的属性经过中间处理,则通过使用空间名字的方法进行赋值
*/
#region 依赖属性定义
public static readonly DependencyProperty ItemsProperty;
public static readonly DependencyProperty DisplayPathProperty;
public static readonly DependencyProperty ChildrenPathProperty;
#endregion
#region 定义命令
private static RoutedCommand m_SelectCommand;
public static RoutedCommand SelectCommand
{
get { return m_SelectCommand; }
}
#endregion
#region 定义事件
public static readonly RoutedEvent SelectChangedEvent = EventManager.RegisterRoutedEvent("SelectChanged",
RoutingStrategy.Direct, typeof(RoutedPropertyChangedEventHandler), typeof(TreeCategory));
#endregion
static TreeCategory()
{
ItemsProperty = DependencyProperty.Register("Items", typeof(IEnumerable), typeof(TreeCategory), new PropertyMetadata(default(IEnumerable), new PropertyChangedCallback(PropertyChangedCallback)));
DisplayPathProperty = DependencyProperty.Register("DisplayPath", typeof(string), typeof(TreeCategory), new PropertyMetadata(default(string), new PropertyChangedCallback(PropertyChangedCallback)));
ChildrenPathProperty = DependencyProperty.Register("ChildrenPath", typeof(string), typeof(TreeCategory), new PropertyMetadata(default(string), new PropertyChangedCallback(PropertyChangedCallback)));
m_SelectCommand = new RoutedCommand("SelectCommand", typeof(TreeCategory));
System.Windows.Input.CommandManager.RegisterClassCommandBinding(typeof(TreeCategory), new CommandBinding(m_SelectCommand, OnSelectCommand, CanExecuteRoutedEventHandler));
HeightProperty.OverrideMetadata(typeof(TreeCategory), new FrameworkPropertyMetadata(120d, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(HeightPropertyChangedCallback)));
}
#region 依赖属性封装
///
/// 控件包好项目
///
public IEnumerable Items
{
get { return (IEnumerable)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
///
/// 类型显示字段
///
public string DisplayPath
{
get { return (string)GetValue(DisplayPathProperty); }
set { SetValue(DisplayPathProperty, value); }
}
///
/// 控件选中项目
///
public IList SelectItems { get; private set; }
///
/// 子集合路径
///
public string ChildrenPath
{
get { return (string)GetValue(ChildrenPathProperty); }
set { SetValue(ChildrenPathProperty, value); }
}
#endregion
#region 事件封装
public event RoutedPropertyChangedEventHandler SelectChanged
{
add { this.AddHandler(SelectChangedEvent, value); }
remove { this.RemoveHandler(SelectChangedEvent, value); }
}
#endregion
#region 相关静态方法
#region 属性变化与界面关联
private static void HeightPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
TreeCategory section = sender as TreeCategory;
if (section != null)
{
section.tree.Height = (double)args.NewValue;
}
}
private static void PropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
TreeCategory tree = sender as TreeCategory;
if (tree != null)
{
string propeertyName = args.Property.Name;
switch (propeertyName)
{
case "Items":
{
object tempObject = args.NewValue;
if (tempObject == null)
{
tree.DisplayItemsSource = null;
tree.SelectItems = null;
tree.tree.ItemsSource = null;
break;
}
var type = tempObject.GetType().GetInterface(typeof(IEnumerable).Name);
if (type == null)
{
throw new Exception("数据源需要实现IEnumerable接口");
}
tree.InitSource((IEnumerable)tempObject,tree.DisplayPath, tree.ChildrenPath);
break;
}
case "ChildrenPath":
{
string tempObject = args.NewValue as string;
if (tree.Items == null)
break;
tree.InitSource(tree.Items, tree.DisplayPath, tempObject);
break;
}
case "DisplayPath":
{
string tempObject = args.NewValue as string;
if (tree.Items == null)
break;
tree.InitSource(tree.Items, tempObject, tree.ChildrenPath);
break;
}
}
}
}
#endregion
#endregion
#region 命令处理
private static void OnSelectCommand(object sender, ExecutedRoutedEventArgs e)
{
TreeCategory list = sender as TreeCategory;
if (list != null)
{
InnerCheckItem item = e.Parameter as InnerCheckItem;
if (item != null)
{
item.CheckedChanged();
}
list.ChangeSelectItems();
}
}
private static void CanExecuteRoutedEventHandler(object sender, CanExecuteRoutedEventArgs e)
{
e.CanExecute = true;
}
#endregion
#region 私有属性
private ObservableCollection DisplayItemsSource { get; set; }
#endregion
#region 类型私有方法集合
private void InitSource(IEnumerable source,string namePath, string childPath)
{
/*
* 这种分两种情况考虑递归的方式,是因为,最顶层可能不存在根节点。所以顶层数据结构需要特殊处理
*/
if (source == null)
{
this.DisplayItemsSource = null;
return;
}
childPath = childPath ?? "";
IEnumerator enumerator = ((IEnumerable)source).GetEnumerator();
try
{
var tempSource = new ObservableCollection();
while (enumerator.MoveNext())
{
var tempCurrent = enumerator.Current;
if (tempCurrent != null)
{
Type type = tempCurrent.GetType();
PropertyInfo propertyInfo = type.GetProperty(childPath);
if (propertyInfo == null || propertyInfo.PropertyType.GetInterface(typeof(IEnumerable).Name) == null)
{
tempSource.Add(new InnerCheckItem(tempCurrent, namePath));
}
else
{
InnerCheckItemCollection tempCollection;
tempSource.Add(tempCollection = new InnerCheckItemCollection(tempCurrent, namePath));
object children = propertyInfo.GetValue(tempCurrent, null);
IEnumerator enumeratorCollection = ((IEnumerable)children).GetEnumerator();
try
{
while (enumeratorCollection.MoveNext())
{
var tempCurrentCollection = enumeratorCollection.Current;
if (tempCurrentCollection != null)
{
InitSource(tempCollection, tempCurrentCollection, namePath, childPath);
}
}
}
catch (Exception)
{
}
finally
{
enumeratorCollection.Reset();
}
}
}
}
this.DisplayItemsSource = tempSource;
}
finally
{
enumerator.Reset();
}
this.tree.ItemsSource = this.DisplayItemsSource;
this.SelectItems = null;
}
private void InitSource(InnerCheckItemCollection collection, object obj,string namePath, string childPath)
{
Type type = obj.GetType();
PropertyInfo propertyInfo = type.GetProperty(childPath);
if (propertyInfo == null || propertyInfo.PropertyType.GetInterface(typeof(IEnumerable).Name) == null)
{
collection.AddItem(new InnerCheckItem(obj, namePath));
}
else
{
InnerCheckItemCollection tempCollection;
collection.AddItem(tempCollection = new InnerCheckItemCollection(obj, namePath));
IEnumerator enumerator = ((IEnumerable)obj).GetEnumerator();
while (enumerator.MoveNext())
{
var tempCurrent = enumerator.Current;
if (tempCurrent != null)
{
InitSource(tempCollection, tempCurrent,namePath, childPath);
}
}
}
}
#endregion
#region 公开selectChange事件
private void ChangeSelectItems()
{
List tempObjects = new List();
List tempSource=new List(this.DisplayItemsSource);
for (int i = 0; i < tempSource.Count; i++)
{
InnerCheckItem tempItem = tempSource[i];
if (tempItem is InnerCheckItemCollection)
{
tempSource.AddRange(((InnerCheckItemCollection)tempItem).Items);
continue;
}
if (tempItem.IsChecked)
{
tempObjects.Add(tempItem.RefObject);
continue;
}
}
object oldValue = this.SelectItems;
this.SelectItems = tempObjects;
OnSelectChanged(oldValue, this.SelectItems);
}
protected virtual void OnSelectChanged(object oldValue, object newValue)
{
RoutedPropertyChangedEventArgs arg = new RoutedPropertyChangedEventArgs(oldValue, newValue, SelectChangedEvent);
this.RaiseEvent(arg);
}
#endregion
#region 选择实例方法
///
/// 获取所有叶子节点
///
///
private List GetAllLeaf()
{
List leaves = new List();
if (this.DisplayItemsSource == null)
{
return leaves;
}
foreach (var innerCheckItem in DisplayItemsSource)
{
GetAllLeaf(leaves, innerCheckItem);
}
return leaves;
}
private void GetAllLeaf(List list, InnerCheckItem item)
{
if (item == null) return;
InnerCheckItemCollection tempCollection = item as InnerCheckItemCollection;
if (tempCollection != null)
{
foreach (InnerCheckItem innerCheckItem in tempCollection.Items)
{
GetAllLeaf(list, innerCheckItem);
}
return;
}
list.Add(item);
}
///
/// 设置选中项
///
///
public void SetSelected(object o)
{
var allLeaf = GetAllLeaf();
foreach (var innerCheckItem in allLeaf)
{
if (innerCheckItem.RefObject.Equals(o))
{
innerCheckItem.IsChecked = true;
}
}
allLeaf.ForEach(leaf => leaf.CheckedChanged());
}
///
/// 设定选中元素
///
///
///
///
public void SetSelected(T o, IEqualityComparer compare) where T : class
{
var allLeaf = GetAllLeaf();
foreach (var innerCheckItem in allLeaf)
{
T tempRef = innerCheckItem.RefObject as T;
if (compare != null && tempRef != null && compare.Equals(tempRef, o))
{
innerCheckItem.IsChecked = true;
}
}
allLeaf.ForEach(leaf => leaf.CheckedChanged());
}
///
/// 设置选中集合
///
///
///
public void SetSelected(IList selectList, IEqualityComparer compare) where T : class
{
var allLeaf = GetAllLeaf();
foreach (var innerCheckItem in DisplayItemsSource)
{
T tempRef = innerCheckItem.RefObject as T;
if (tempRef == null)
continue;
foreach (T o in selectList)
{
if (compare != null && compare.Equals(tempRef, o))
{
innerCheckItem.IsChecked = true;
}
}
}
allLeaf.ForEach(leaf => leaf.CheckedChanged());
}
///
/// 设置选中集合
///
///
public void SetSelected(IList selectList)
{
var allLeaf = GetAllLeaf();
foreach (var innerCheckItem in DisplayItemsSource)
{
if (selectList.Contains(innerCheckItem.RefObject))
{
innerCheckItem.IsChecked = true;
}
}
allLeaf.ForEach(leaf => leaf.CheckedChanged());
}
private void SetAllElementChecked(bool isChecked,bool turnChecked=false)
{
bool flag = isChecked;
if (DisplayItemsSource == null)
return;
var tempSource = new List(this.DisplayItemsSource);
for (int i = 0; i < tempSource.Count; i++)
{
var tempItem = tempSource[i];
if (isChecked)
{
flag = !tempItem.IsChecked;
}
tempItem.IsChecked = flag;
InnerCheckItemCollection collection = tempItem as InnerCheckItemCollection;
if (collection != null)
{
tempSource.AddRange(collection.Items);
}
}
}
///
/// 选中所有元素
///
public void CheckAll()
{
SetAllElementChecked(true);
ChangeSelectItems();
}
///
/// 去除所有选中元素
///
public void CheckNone()
{
SetAllElementChecked(false);
ChangeSelectItems();
}
///
/// 反选
///
public void CheckTurn()
{
SetAllElementChecked(false,true);
var allLeaf = GetAllLeaf();
allLeaf.ForEach(leaf => leaf.CheckedChanged());
ChangeSelectItems();
}
#endregion
}
}