WPF 组织机构下拉树多选
Posted 秋荷雨翔的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 == 0); 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() > 0) { 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(0, 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 > 0) { 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(100); } this.Dispatcher.BeginInvoke(new Action(() => { if (Nodes == null) { foreach (MultiSelOrgTreeItemModel item in _collection[0].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 组织机构下拉树多选的主要内容,如果未能解决你的问题,请参考以下文章
WPF 实现可以多选的 Combo box 有啥好的思路或解决方案
WPF combox 绑定checkbox(多选已经实现), 当在Selecte ComboboxItem而非Check的时候,显示checkbox。