使用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;
}
}
效果图: