WPF 组织机构下拉树多选,递归绑定方式现实
使用HierarchicalDataTemplate递归绑定现实
XAML代码:
<UserControl x:Class="SunCreate.CombatPlatform.Client.MultiSelOrgTree"
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:ui="clr-namespace:SunCreate.CombatPlatform.Client"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="200">
<Grid>
<Button x:Name="btnSelected" Click="BtnClick" Height="25">
<Button.Template>
<ControlTemplate>
<Border Height="{TemplateBinding Property=Height}">
<Border.Background>
<ImageBrush ImageSource="/SunCreate.CombatPlatform.Client.Resources;component/Image/Face/Enter.png"/>
</Border.Background>
<TextBlock Margin="3 0 0 0" Text="{TemplateBinding Property=Tag}" Foreground="#1ba4f6" VerticalAlignment="Center"></TextBlock>
</Border>
</ControlTemplate>
</Button.Template>
</Button>
<Popup x:Name="popup" StaysOpen="False" PopupAnimation="Scroll" Width="280" Height="300" AllowsTransparency="True">
<Border Background="#00234E" BorderThickness="1" BorderBrush="#224066">
<TreeView x:Name="orgTree" >
<TreeView.Template>
<ControlTemplate>
<ScrollViewer HorizontalScrollBarVisibility="Auto" MinHeight="{Binding ElementName=orgTree,Path=ActualHeight}" MinWidth="{Binding ElementName=orgTree, Path=ActualWidth}">
<ItemsPresenter></ItemsPresenter>
</ScrollViewer>
</ControlTemplate>
</TreeView.Template>
<TreeView.ItemTemplate>
<HierarchicalDataTemplate DataType="{x:Type ui:MultiSelOrgTreeItemModel}" ItemsSource="{Binding Path=Nodes}" >
<Border Height="25" Width="200">
<Grid VerticalAlignment="Center" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto"></ColumnDefinition>
<ColumnDefinition Width="15"></ColumnDefinition>
<ColumnDefinition ></ColumnDefinition>
</Grid.ColumnDefinitions>
<CheckBox Visibility="{Binding Path=CheckVisiable}" Tag="{Binding}" IsChecked="{Binding Path=IsChecked, Mode=TwoWay}" Click="cxb_Node_Click" Checked="cxb_Node_Checked" Unchecked="cxb_Node_UnChecked"></CheckBox>
<Image Grid.Column="1" Width="10" Height="10" Source="/SunCreate.CombatPlatform.Client.Resources;component/Image/orgIcon.png"></Image>
<TextBlock Grid.Column="2" FontSize="12" VerticalAlignment="Center" Margin="10,0,0,0" x:Name="Name" Foreground="White" Text="{Binding Path=Name}"></TextBlock>
</Grid>
</Border>
</HierarchicalDataTemplate>
</TreeView.ItemTemplate>
</TreeView>
</Border>
</Popup>
</Grid>
</UserControl>
后台代码:
using SunCreate.pahf.Domain;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes; namespace SunCreate.CombatPlatform.Client
{
/// <summary>
/// 组织机构树多选
/// </summary>
public partial class MultiSelOrgTree : UserControl
{
private bool _firstLoad = true;
private log4net.ILog _log = log4net.LogManager.GetLogger(typeof(MultiSelOrgTree));
private ObservableCollection<MultiSelOrgTreeItemModel> _collection = new ObservableCollection<MultiSelOrgTreeItemModel>();
private ObservableCollection<PT_ORG_INFO> _selectedOrgs = new ObservableCollection<PT_ORG_INFO>();
private bool _inited = false; public IList<PT_ORG_INFO> SelectedOrgs
{
get { return _selectedOrgs; }
} public MultiSelOrgTree()
{
InitializeComponent(); this.Loaded += MultiSelOrgTree_Loaded;
this.orgTree.Loaded += orgTree_Loaded;
} private void MultiSelOrgTree_Loaded(object sender, RoutedEventArgs e)
{
if (_firstLoad)
{
_firstLoad = false;
InitData();
}
} private void InitData()
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
var list = SP.Get<Cache.ICacheService>().OrgCache.GetCameraOrgs();
var info = list.FirstOrDefault(p => p.PAR_ID == );
MultiSelOrgTreeItemModel root = new MultiSelOrgTreeItemModel();
root.Info = info;
root.Name = info.ORG_NAME;
BuildTree(root, list);
_collection.Add(root);
Dispatcher.BeginInvoke(new Action(() =>
{
this.orgTree.ItemsSource = root.Nodes;
_inited = true;
}));
});
} private void orgTree_Loaded(object sender, RoutedEventArgs e)
{
ExpandInternal(this.orgTree);
} private void BuildTree(MultiSelOrgTreeItemModel root, IList<PT_ORG_INFO> orgs)
{
var children = orgs.Where(p => p.PAR_ID == root.Info.ID);
if (children != null && children.Count() > )
{
foreach (var item in children)
{
MultiSelOrgTreeItemModel model = new MultiSelOrgTreeItemModel();
model.Info = item;
model.Name = item.ORG_NAME;
model.IsChecked = false;
model.Parent = root;
BuildTree(model, orgs);
root.Nodes.Add(model);
}
}
else
{
root.IsLeaf = true;
}
} /// <summary>
/// 展开树节点
/// </summary>
/// <param name="targetItemContainer"></param>
private void ExpandInternal(System.Windows.Controls.ItemsControl targetItemContainer)
{
try
{
if (targetItemContainer == null) return;
if (targetItemContainer.Items == null) return;
foreach (Object item in targetItemContainer.Items)
{
System.Windows.Controls.TreeViewItem treeItem = targetItemContainer.ItemContainerGenerator.ContainerFromItem(item) as TreeViewItem;
var info = item as TreeNode;
if (treeItem == null || !treeItem.HasItems)
{
continue;
}
//if (info.Info == null)
//{
// treeItem.Foreground = new SolidColorBrush((Color)ColorConverter.ConvertFromString("#2ad7fa"));
//}
treeItem.IsExpanded = true;
//ExpandInternal(treeItem as ItemsControl);
}
}
catch (Exception ex)
{
_log.ErrorFormat("ExpandInternal error", ex);
}
} private void cxb_Node_UnChecked(object sender, RoutedEventArgs e) { } private void cxb_Node_Checked(object sender, RoutedEventArgs e) { } private void cxb_Node_Click(object sender, RoutedEventArgs e)
{
try
{
CheckBox cbx = sender as CheckBox;
var node = (sender as CheckBox).Tag as MultiSelOrgTreeItemModel;
if (node != null && cbx.IsChecked != null)
{
if (cbx.IsChecked.Value)
{
if (!_selectedOrgs.Contains(node.Info))
{
_selectedOrgs.Add(node.Info);
CheckChild(node, true);
}
}
else
{
if (_selectedOrgs.Contains(node.Info))
{
_selectedOrgs.Remove(node.Info);
CheckChild(node, false);
}
}
CheckParent(node);
btnSelected.Tag = string.Join(",", _selectedOrgs.ToList().ConvertAll(a => a.ORG_NAME));
}
}
catch (Exception ex)
{ }
} private void CheckParent(MultiSelOrgTreeItemModel node)
{
if (node.Parent != null)
{
bool isCheck = true;
foreach (MultiSelOrgTreeItemModel item in node.Parent.Nodes)
{
if (!item.IsChecked)
{
isCheck = false;
}
}
if (isCheck)
{
node.Parent.IsChecked = true;
if (!_selectedOrgs.Contains(node.Parent.Info))
{
_selectedOrgs.Insert(, node.Parent.Info);
}
}
else
{
node.Parent.IsChecked = false;
if (_selectedOrgs.Contains(node.Parent.Info))
{
_selectedOrgs.Remove(node.Parent.Info);
}
}
btnSelected.Tag = string.Join(",", _selectedOrgs.ToList().ConvertAll(a => a.ORG_NAME));
if (node.Parent.Parent != null)
{
CheckParent(node.Parent);
}
}
} private void CheckChild(MultiSelOrgTreeItemModel node, bool isCheck)
{
if (node.Nodes.Count > )
{
if (isCheck)
{
foreach (MultiSelOrgTreeItemModel item in node.Nodes)
{
item.IsChecked = true;
if (!_selectedOrgs.Contains(item.Info))
{
_selectedOrgs.Add(item.Info);
}
CheckChild(item, true);
}
}
else
{
foreach (MultiSelOrgTreeItemModel item in node.Nodes)
{
item.IsChecked = false;
if (_selectedOrgs.Contains(item.Info))
{
_selectedOrgs.Remove(item.Info);
}
CheckChild(item, false);
}
}
}
} private void BtnClick(object sender, RoutedEventArgs e)
{
popup.PlacementTarget = sender as Button;
popup.Placement = PlacementMode.Bottom;
popup.IsOpen = true;
} public void Select(List<string> orgIdList, ObservableCollection<MultiSelOrgTreeItemModel> Nodes = null)
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
while (!_inited)
{
System.Threading.Thread.Sleep();
}
this.Dispatcher.BeginInvoke(new Action(() =>
{
if (Nodes == null)
{
foreach (MultiSelOrgTreeItemModel item in _collection[].Nodes)
{
if (orgIdList.Exists(a => a == item.Info.ID.ToString()))
{
item.IsChecked = true;
if (!_selectedOrgs.Contains(item.Info))
{
_selectedOrgs.Add(item.Info);
}
}
else
{
item.IsChecked = false;
if (_selectedOrgs.Contains(item.Info))
{
_selectedOrgs.Remove(item.Info);
}
}
Select(orgIdList, item.Nodes);
}
}
else
{
foreach (MultiSelOrgTreeItemModel item in Nodes)
{
if (orgIdList.Exists(a => a == item.Info.ID.ToString()))
{
item.IsChecked = true;
if (!_selectedOrgs.Contains(item.Info))
{
_selectedOrgs.Add(item.Info);
}
}
else
{
item.IsChecked = false;
if (_selectedOrgs.Contains(item.Info))
{
_selectedOrgs.Remove(item.Info);
}
}
Select(orgIdList, item.Nodes);
}
}
btnSelected.Tag = string.Join(",", _selectedOrgs.ToList().ConvertAll(a => a.ORG_NAME));
}));
});
}
} public class MultiSelOrgTreeItemModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged; public MultiSelOrgTreeItemModel()
{
_nodes = new ObservableCollection<MultiSelOrgTreeItemModel>();
_parent = null;
} private ObservableCollection<MultiSelOrgTreeItemModel> _nodes;
public ObservableCollection<MultiSelOrgTreeItemModel> Nodes
{
get { return _nodes; }
set
{
this._nodes = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Nodes"));
}
}
} private MultiSelOrgTreeItemModel _parent;
public MultiSelOrgTreeItemModel Parent
{
get { return _parent; }
set
{
this._parent = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Parent"));
}
}
} /// <summary>
/// 名称
/// </summary>
public string _name;
public string Name
{
get { return _name; }
set
{
this._name = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Name"));
}
}
} /// <summary>
/// 是否是叶子
/// </summary>
public bool _isLeaf;
public bool IsLeaf
{
get { return _isLeaf; }
set
{
this._isLeaf = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("IsLeaf"));
}
if (value)
{
CheckVisiable = Visibility.Visible;
}
}
} /// <summary>
/// 选择框是否可见
/// </summary>
public Visibility _checkVisiable = Visibility.Visible;
public Visibility CheckVisiable
{
get { return _checkVisiable; }
set
{
this._checkVisiable = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("CheckVisiable"));
}
}
} /// <summary>
/// 是否选中
/// </summary>
public bool _isChecked;
public bool IsChecked
{
get { return _isChecked; }
set
{
this._isChecked = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
} public PT_ORG_INFO Info;
}
}
效果图:

WPF 组织机构下拉树多选,递归绑定方式现实的更多相关文章
- layui扩展组件,下拉树多选
项目介绍 项目中需要用到下拉树多选功能,找到两个相关组件moretop-layui-select-ext和wujiawei0926-treeselect,但是moretop-layui-selec ...
- vue 模拟下拉树
// 使用vue 做表格部分其他部分暂不修改 var app = new Vue({ el: "#freightTbl", watch: { //监听表格数据的变化[使用 watc ...
- vue-Treeselect实现组织机构(员工)下拉树的功能
知识点:前端使用vuetree的组件库,调用后台查询组织机构,包括人员的接口 实现下拉树的功能 查考: vue-treeselect官网:https://vue-treeselect.js.org/ ...
- vue+element下拉树选择器
项目需求:输入框点击弹出树形下拉结构,可多选或者单选. 解决方案:1.使用layui formSelect多选插件 2.基于vue+elementui 下拉框和树形控件组合成树形下拉结构 <el ...
- EasyUI-combotree 下拉树 数据回显时默认选中
组合树(combotree)把选择控件和下拉树结合起来.它与组合框(combobox)相似,不同的是把列表替换成树组件.组合树(combotree)支持带有用于多选的树状态复选框的树. 依赖 comb ...
- elementUI下拉树组件封装
使用组件:Popover 弹出框.Tree 树形控件 和 input 输入框 用法: 1.新建一个.vue文件,粘贴以下组件封装的代码(完全可以使用) 2.在页面需要使用下拉树的地方调用即可. (1) ...
- jquery实现下拉框多选
一.说明 本文是利用EasyUI实现下拉框多选功能,在ComboxTree其原有的基础上对样式进行了改进,样式表已上传demo,代码如下 二.代码 <!DOCTYPE html PUBLIC & ...
- zTree开发下拉树
最近,因为工作需要一个树形下拉框的组件,经过查资料一般有两种的实现方法.其一,就是使用zTree实现:其二,就是使用easyUI实现.因为公司的前端不是使用easyUI设计的,故这里我选择了zTree ...
- combobox中动态加入几个checkbox,实现下拉框多选
combobox中动态加入几个checkbox,实现下拉框多选,将一个checkbox选中时其内容就会在combobox中显示出来,将另一个checkbox选中时其内容会跟在第一个checkbox的内 ...
随机推荐
- Ansible 系列之 Inventory 资源清单介绍
一.Inventory 库存清单文件 1.Inventory 作用 Ansible 可以在同一时间针对多个系统设施进行管理工作.它通过选择Ansible 资源清单文件中列出的系统,该清单文件默认是在/ ...
- python3操作MySQL数据库
安装PyMySQL 下载地址:https://pypi.python.org/pypi/PyMySQL 1.把操作Mysql数据库封装成类,数据库和表先建好 import pymysql.cursor ...
- PHP 成长规划
PHP程序员的技术成长规划 作者:黑夜路人(2014/10/15) 转:http://blog.csdn.net/heiyeshuwu/article/details/40098043 按照了解的很多 ...
- Spring Boot 16 条最佳实践
Spring Boot是最流行的用于开发微服务的Java框架.在本文中,我将与你分享自2016年以来我在专业开发中使用Spring Boot所采用的最佳实践.这些内容是基于我的个人经验和一些熟知的Sp ...
- padding margin border 和元素大小
元素占用宽度 = 元素宽度+padding+border+margin 注意margin只是隔开元素,不会使得元素变大,而padding会使得元素变大,也就是说 元素真实宽度=元素宽度+padding ...
- 01-E-1: 迭代与递归
- UITextFeild银行卡/身份证/电话号任意分割.
日常开发中可能有个需求, 1.银行卡每4位添加一个空格 2.电话号:3 4 4 比如(138 8888 8888)3.身份证(411111 20171213 1314) 看了网上许多方法都是输入的时 ...
- C++中public、protected以及private的使用
相比C语言,C++中通过class/struct来定义既包含数据,又包含行为的结构,从而支持了“对象”.现实世界中,一个人(一个对象)通常 拥有一些资产(数据),并且掌握某些技能(行为),并且这些资产 ...
- 使用twised实现一个EchoServer
ProtocolsProtocols描述了如何以异步的方式处理网络中断时间,HTTP.DNS已经IMAP是应用应用层协议中的例子,Protocols实现了IProtocol接口,它饱和如下的方法 ma ...
- java高级工程师(一)
一.无笔试题 不知道是不是职位原因还是没遇到,面试时,都不需要做笔试题,而是填张个人信息表格,或者直接面试 二.三大框架方面问题 1.Spring 事务的隔离性,并说说每个隔离性的区别 ...