标签:mon bin clear tor tom 指定 ems sch enum
工作中要为很多类创建TreeView, 很多时候仅仅是因为要显示字段不同, 就得Ctrl+C、Ctrl+V复制一份几乎相同的代码, 这难免让人生厌, 于是希望像泛型集合的扩展方法那样, 可以在使用的时候灵活指定要显示哪个字段.
下面的TreeView要实现这样的逻辑: 父项目 被勾选 或者 取消勾选, 那么它的所有子项目全部改成 被勾选 或者 取消勾选; 只有所有的子项目都被勾选时, 父项目才自发的改成被勾选
/// <summary>
/// 通用的TreeViewItem模型, 仅包含最基础CheckBox(如果你觉得不好看, 在CommonTreeView.xaml中修改样式), 还包含一个 Tag(包含的对象)
/// 业务逻辑: 父项目 被勾选 或者 取消勾选, 那么它的所有子项目全部改成 被勾选 或者 取消勾选; 只有所有的子项目都被勾选时, 父项目才自发的改成被勾选
/// 所有的字段都改为protected, 方便继承修改
/// </summary>
public class CommonTreeViewItemModel : INotifyPropertyChanged
{
#region 属性
public event PropertyChangedEventHandler PropertyChanged;
protected object id;
/// <summary>
/// 唯一性Id
/// </summary>
public object Id
{
get { return id; }
set { id = value; }
}
protected string caption;
/// <summary>
/// 标题
/// </summary>
public string Caption
{
get { return caption; }
set { caption = value; if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("Caption")); }
}
protected bool isChecked;
/// <summary>
/// 是否被勾选
/// </summary>
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsChecked"));
SetIsCheckedByParent(value);
if (Parent != null) Parent.SetIsCheckedByChild(value);
}
}
protected bool isExpanded;
/// <summary>
/// 是否被展开
/// </summary>
public bool IsExpanded
{
get { return isExpanded; }
set { isExpanded = value; if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsExpanded")); }
}
protected CommonTreeViewItemModel parent;
/// <summary>
/// 父项目
/// </summary>
public CommonTreeViewItemModel Parent
{
get { return parent; }
set { parent = value; }
}
protected List<CommonTreeViewItemModel> children = new List<CommonTreeViewItemModel>();
/// <summary>
/// 含有的子项目
/// </summary>
public List<CommonTreeViewItemModel> Children
{
get { return children; }
set { children = value; }
}
/// <summary>
/// 包含的对象
/// </summary>
public object Tag { get; set; }
/// <summary>
/// 包含对象的类型
/// </summary>
public Type TagType { get; set; }
#endregion
#region 业务逻辑, 如果你需要改成其他逻辑, 要修改的也就是这两行
/// <summary>
/// 子项目的isChecked改变了, 通知 是否要跟着改变 isChecked
/// </summary>
/// <param name="value"></param>
public virtual void SetIsCheckedByChild(bool value)
{
if (this.isChecked == value)
{
return;
}
bool isAllChildrenChecked = this.Children.All(c => c.IsChecked == true);
this.isChecked = isAllChildrenChecked;
if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsChecked"));
if (Parent != null) Parent.SetIsCheckedByChild(value);
}
/// <summary>
/// 自己的isChecked改变了, 所有子项目都要跟着改变
/// </summary>
/// <param name="value"></param>
public virtual void SetIsCheckedByParent(bool value)
{
this.isChecked = value;
if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs("IsChecked"));
foreach (var child in Children)
{
child.SetIsCheckedByParent(value);
}
}
#endregion
}
public partial class CommonTreeView : UserControl
{
public IList<CommonTreeViewItemModel> ItemsSourceData
{
get { return (IList<CommonTreeViewItemModel>)innerTree.ItemsSource; }
}
public CommonTreeView()
{
InitializeComponent();
}
/// <summary>
/// 设置数据源, 以及各个字段
/// </summary>
/// <typeparam name="TSource">数据源类型</typeparam>
/// <typeparam name="TId">主键类型</typeparam>
/// <param name="itemsArray">数据源列表</param>
/// <param name="captionSelector">指定显示为Caption的属性</param>
/// <param name="idSelector">指定主键属性</param>
/// <param name="parentIdSelector">指定父项目主键属性</param>
public void SetItemsSourceData<TSource, TId>(IEnumerable<TSource> itemsArray, Func<TSource, string> captionSelector, Func<TSource, TId> idSelector, Func<TSource, TId> parentIdSelector)
where TId : IEquatable<TId>
{
var list = new List<CommonTreeViewItemModel>();
foreach (var item in itemsArray.Where(a => object.Equals(default(TId), parentIdSelector(a))))
{
var tvi = new CommonTreeViewItemModel();
tvi.Caption = captionSelector(item).ToString();
tvi.Id = idSelector(item);
tvi.Tag = item;
tvi.TagType = item.GetType();
list.Add(tvi);
RecursiveAddChildren(tvi, itemsArray, captionSelector, idSelector, parentIdSelector);
}
innerTree.ItemsSource = list;
return;
}
/// <summary>
/// 递归加载children
/// </summary>
/// <typeparam name="TSource"></typeparam>
/// <typeparam name="TId"></typeparam>
/// <param name="parent"></param>
/// <param name="itemsArray"></param>
/// <param name="captionSelector"></param>
/// <param name="idSelector"></param>
/// <param name="parentIdSelector"></param>
/// <returns></returns>
private CommonTreeViewItemModel RecursiveAddChildren<TSource, TId>(CommonTreeViewItemModel parent, IEnumerable<TSource> itemsArray, Func<TSource, string> captionSelector, Func<TSource, TId> idSelector, Func<TSource, TId> parentIdSelector)
{
foreach (var item in itemsArray.Where(a => parent.Id.Equals(parentIdSelector(a))))
{
var tvi = new CommonTreeViewItemModel();
tvi.Caption = captionSelector(item);
tvi.Id = idSelector(item);
tvi.Tag = item;
tvi.TagType = item.GetType();
tvi.Parent = parent;
parent.Children.Add(tvi);
RecursiveAddChildren(tvi, itemsArray, captionSelector, idSelector, parentIdSelector);
}
return parent;
}
<UserControl x:Class="WPFCommonTreeView.CommonTreeView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPFCommonTreeView"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<TreeView Name="innerTree">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}"></Setter>
</Style>
</TreeView.ItemContainerStyle>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type local:CommonTreeViewItemModel}" ItemsSource="{Binding Children}">
<CheckBox FontSize="14" FontFamily="微软雅黑" Tag="{Binding Children}" IsChecked="{Binding IsChecked, Mode=TwoWay}" Content="{Binding Caption}" />
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Grid>
</UserControl>
后记: 说实在的, 这个通用TreeView其实一点也不通用, 简单倒是真的, 主要原因是实际业务中TreeView的层次和逻辑千差万别, 就当自己的一点尝试吧.
转载请注明出处: http://www.cnblogs.com/zhouandke/p/6201064.html
标签:mon bin clear tor tom 指定 ems sch enum
原文地址:http://www.cnblogs.com/zhouandke/p/6201064.html