您的位置:首页 > 其它

silverlight 中 ComboBox+TreeView 实现的下拉控件

2010-09-25 10:58 363 查看
功能描述:

ComboBox+TreeView实现的用户控件,设置数据源后,可以递归加载数据,支持双向绑定

控件截图:



XAML界面设计:

<UserControl x:Class="ChuanyeOA.CustomControls.ComboBoxTree"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
d:DesignHeight="30" d:DesignWidth="300" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

<Grid x:Name="LayoutRoot">
<ComboBox Height="23" Name="cbMain" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" DropDownOpened="cbMain_DropDownOpened" DropDownClosed="cbMain_DropDownClosed">
<ComboBoxItem x:Name="cbItemTreeView">
<ComboBoxItem.Content>
<sdk:TreeView Name="tvList" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" SelectedItemChanged="tvList_SelectedItemChanged" />
</ComboBoxItem.Content>
</ComboBoxItem>

<ComboBoxItem x:Name="cbItemDisplay" >
</ComboBoxItem>
</ComboBox>
</Grid>
</UserControl>


后台CS代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

using System.Windows.Data;

using System.Collections;
using System.Reflection;

/********************************
* 创建人:刘跃飞
* 创建时间:2010-09-21
* 功能描述:ComboBox+TreeView实现的用户控件,主要实现选择TreeView中的项做为ComboBox的项的功能
* 属性描述:此控件包含以下几个属性
* 1.ItemsSource:控件要绑定的数据源
* 2.SelectedValuePath:选中的值的属性
* 3.DisplayMemberPath:获取或设置为每个数据项要显示的属性的名称
* 4.SelectedItem  当前选择的项
* 5.SelectedValue  当前选择的值
* 6.IsRecursionEnabled 设置是否启用递归加载数据源中的项 。需要设置ChildName和ParentName两个属性
* 7.ChildMemberPath 递归加载数据源时,实体中的子级属性项
* 8. ParentMemberPath 递归加载数据源时,实体中的父级属性项
* 9.IsExpandAll 设置TreeView打开时是全部打开状态还是收缩状态 默认为True打开状态
*
* 使用方法:
* 注意事项:本控件设计尚不完善,【ItemsSource】属性需要在最后设置,否则,将提示错误
* 1.界面上直接设置,例如:
*  <myControl:ComboBoxTree SelectedValue="{Binding DepartmentID, Mode=TwoWay}" DisplayMemberPath="DepartName" SelectedValuePath="ID" IsRecursionEnabled="True" ChildMemberPath="ID" ParentMemberPath="ParentID"  ItemsSource="{Binding Data, Source={StaticResource a_DepartmentDomainDataSource}}">
* 2.在后台代码中直接设置,例如:
*           comboBoxTree1.DisplayMemberPath = "Name";
*           comboBoxTree1.SelectedValuePath = "ID";
*           comboBoxTree1.ChildMemberPath = "ID";
*           comboBoxTree1.ParentMemberPath = "ParentID";
*           comboBoxTree1.IsRecursionEnabled = true;
*           comboBoxTree1.ItemSource = MyControls.DepartmentInfo.GetDepartment().AsEnumerable();
* 3.如果启用递归加载,父级ID为【0】的项,将作为根节点加载,如果没有父级ID为【0】的项,将无法进行加载
* 4.此控件用到了TreeView的ExpandAll扩展方法,需要添加【System.Windows.Controls.Toolkit】类库的引用,否则将提示找不到此方法
* ***********************************/

namespace ChuanyeOA.CustomControls
{
public partial class ComboBoxTree : UserControl
{
public ComboBoxTree()
{
InitializeComponent();

this.LayoutUpdated += new EventHandler(ComboBoxTree_LayoutUpdated);
}

void ComboBoxTree_LayoutUpdated(object sender, EventArgs e)
{
if (this.IsExpandAll)
{
//--展开所有节点
tvList.ExpandAll();
}
}

#region ItemSource 设置或获得绑定的数据源(属性)

public static readonly DependencyProperty ItemsSourceProperty =
DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ComboBoxTree), new PropertyMetadata(new PropertyChangedCallback(ItemsSourcePropertyChangedCallBack)));
/// <summary>
/// 数据源
/// </summary>
public IEnumerable ItemsSource
{
get
{
return (IEnumerable)this.GetValue(ItemsSourceProperty);
}
set
{
this.SetValue(ItemsSourceProperty, value);
}
}
//--属性更改的回调事件
public static void ItemsSourcePropertyChangedCallBack(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
if (sender != null)
{
ComboBoxTree comboBoxTree = sender as ComboBoxTree;

if (comboBoxTree.IsRecursionEnabled == false)
{
// 以列表的方式加载数据
comboBoxTree.LoadTreeViewDataWithList();
}
else
{
//以递归的方式加载数据
comboBoxTree.LoadTreeViewDataWithRecursion();
}

}
}

#endregion

#region SelectedValuePath  选中的值的属性

public static readonly DependencyProperty SelectedValuePathProperty =
DependencyProperty.Register("SelectedValuePath", typeof(string), typeof(ComboBoxTree), null);
/// <summary>
/// 获取或设置每个属性项要绑定的属性的名称
/// </summary>
public string SelectedValuePath
{
get
{
return (string)this.GetValue(SelectedValuePathProperty);
}
set
{
this.SetValue(SelectedValuePathProperty, value);
}
}

#endregion

#region DisplayMemberPath  获取或设置为每个数据项要显示的属性的名称

public static readonly DependencyProperty DisplayMemberPathProperty =
DependencyProperty.Register("DisplayMemberPath", typeof(string), typeof(ComboBoxTree), null);
/// <summary>
/// 获取或设置为每个数据项要显示的属性的名称
/// </summary>
public string DisplayMemberPath
{
get
{
return (string)this.GetValue(DisplayMemberPathProperty);
}
set
{
this.SetValue(DisplayMemberPathProperty, value);
}
}

#endregion

#region SelectedItem  当前选择的项

public static readonly DependencyProperty SelectedItemProperty =
DependencyProperty.Register("SelectedItem", typeof(object), typeof(ComboBoxTree), null);
/// <summary>
/// 当前选择的项
/// </summary>
public object SelectedItem
{
get
{
return this.GetValue(SelectedItemProperty);
}
set
{
this.SetValue(SelectedItemProperty, value);
}
}

#endregion

#region SelectedValue  当前选择的值

public static readonly DependencyProperty SelectedValueProperty =
DependencyProperty.Register("SelectedValue", typeof(object), typeof(ComboBoxTree), null);
/// <summary>
/// 当前选择的值
/// </summary>
public object SelectedValue
{
get
{
return this.GetValue(SelectedValueProperty);
}
set
{
this.SetValue(SelectedValueProperty, value);
}
}

#endregion

#region IsRecursionEnabled 设置是否启用递归加载数据源中的项 。需要设置ChildName和ParentName两个属性

public static readonly DependencyProperty IsRecursionEnabledProperty =
DependencyProperty.Register("IsRecursionEnabled", typeof(bool), typeof(ComboBoxTree), new PropertyMetadata(new PropertyChangedCallback(IsRecursionEnabledCallBack)));

/// <summary>
/// 设置是否启用递归加载数据源中的项。
/// 需要设置ChildMemberPath和ParentMemberPath两个属性,如果这两个属性没有设置,则不启用递归加载。
/// </summary>
public bool IsRecursionEnabled
{
get
{
return (bool)this.GetValue(IsRecursionEnabledProperty);
}
set
{
//if (value == true)
//{
//    //---如果子级和父级属性设置不为空 则开始递归加载数据
//    if (!string.IsNullOrEmpty(this.ChildMemberPath) && !string.IsNullOrEmpty(this.ParentMemberPath))
//    {
//        if (this.ItemSource != null)
//        {
//            this.LoadTreeViewDataWithRecursion();
//        }
//    }
//}
this.SetValue(IsRecursionEnabledProperty, value);
}
}

public static void IsRecursionEnabledCallBack(DependencyObject sender, DependencyPropertyChangedEventArgs args)
{
if (sender != null)
{
ComboBoxTree comboBoxTree = sender as ComboBoxTree;

comboBoxTree.IsRecursionEnabled = (bool)args.NewValue;
}
}

#endregion

#region ChildMemberPath 递归加载数据源时,实体中的子级属性项

public static readonly DependencyProperty ChildMemberPathProperty =
DependencyProperty.Register("ChildMemberPath", typeof(string), typeof(ComboBoxTree), null);
/// <summary>
/// 递归加载数据源时,实体中的子级属性项
/// </summary>
public string ChildMemberPath
{
get
{
return (string)this.GetValue(ChildMemberPathProperty);
}
set
{
this.SetValue(ChildMemberPathProperty, value);
}
}

#endregion

#region ParentMemberPath 递归加载数据源时,实体中的父级属性项

public static readonly DependencyProperty ParentMemberPathProperty =
DependencyProperty.Register("ParentMemberPath", typeof(string), typeof(ComboBoxTree), null);
/// <summary>
/// 递归加载数据源时,实体中的父级属性项
/// </summary>
public string ParentMemberPath
{
get
{
return (string)this.GetValue(ParentMemberPathProperty);
}
set
{
this.SetValue(ParentMemberPathProperty, value);
}
}

#endregion

#region IsExpandAll 设置TreeView打开时是全部打开状态还是收缩状态 默认为True打开状态
/// <summary>
/// 设置TreeView打开时是全部打开状态还是收缩状态 默认为True打开状态
/// </summary>
public static readonly DependencyProperty IsExpandAllProperty =
DependencyProperty.Register("IsExpandAll", typeof(bool), typeof(ComboBoxTree), new PropertyMetadata(true));
/// <summary>
/// 设置TreeView打开时是全部打开状态还是收缩状态 默认为True打开状态
/// </summary>
public bool IsExpandAll
{
get
{
return (bool)this.GetValue(IsExpandAllProperty);
}
set
{
this.SetValue(IsExpandAllProperty, value);
}
}

#endregion

#region 加载数据源方法

/// <summary>
/// 用列表的方式加载数据源
/// </summary>
private void LoadTreeViewDataWithList()
{
tvList.Items.Clear();//先清空所有的数据

foreach (var item in ItemsSource)
{
Type objType = item.GetType();

//--用反射的方式 获得属性对应的值
PropertyInfo displayMemberInfo = objType.GetProperty(this.DisplayMemberPath);
PropertyInfo selectedValueInfo = objType.GetProperty(this.SelectedValuePath);

//--当前要显示的文本
string displayText = displayMemberInfo.GetValue(item, null).ToString();
//--当前选择的值
string selectedValue = selectedValueInfo.GetValue(item, null).ToString();

TreeViewItem myitem = new TreeViewItem();
myitem.Header = displayText;
myitem.Tag = selectedValue;

tvList.Items.Add(myitem);
}

}

/// <summary>
/// 用递归加载数据源
/// </summary>
private void LoadTreeViewDataWithRecursion()
{
tvList.Items.Clear();//先清空所有的数据

if (ItemsSource != null)
{
//---如果子级和父级属性设置不为空 则开始递归加载数据
if (string.IsNullOrEmpty(this.ChildMemberPath) || string.IsNullOrEmpty(this.ParentMemberPath))
{
MessageBox.Show("在【ComboBoxTree】控件中,如果启用了递归方式加载数据,必须设置【ChildMemberPath】和【ParentMemberPath】属性的值。");
}
foreach (var item in ItemsSource)
{
Type objType = item.GetType();

//--用反射的方式 获得属性对应的值
PropertyInfo displayMemberInfo = objType.GetProperty(this.DisplayMemberPath);
PropertyInfo selectedValueInfo = objType.GetProperty(this.SelectedValuePath);
PropertyInfo childValueInfo = objType.GetProperty(this.ChildMemberPath);
PropertyInfo parentValueInfo = objType.GetProperty(this.ParentMemberPath);

//--当前要显示的文本
string displayText = displayMemberInfo.GetValue(item, null).ToString();
//--当前选择的值
string selectedValue = selectedValueInfo.GetValue(item, null).ToString();
//---子级绑定的值
string childValue = childValueInfo.GetValue(item, null).ToString();
//--父级绑定的值
string parentValue = parentValueInfo.GetValue(item, null).ToString();

if (string.IsNullOrEmpty(childValue) || string.IsNullOrEmpty(parentValue))
{
return;
}
if (parentValue == "0")//--所有的父级的值为【0】的数据默认为添加到根节点。
{
TreeViewItem myitem = new TreeViewItem();
myitem.Header = displayText;
myitem.Tag = selectedValue;
this.LoadItems(myitem, ItemsSource);

tvList.Items.Add(myitem);
}
}
}
}
/// <summary>
/// 递归加载数据源
/// </summary>
/// <param name="treeviewitem"></param>
/// <param name="mylist"></param>
private void LoadItems(TreeViewItem treeviewitem, IEnumerable mylist)
{
if (mylist != null)
{
foreach (var item in ItemsSource)
{
Type objType = item.GetType();

//--用反射的方式 获得属性对应的值
PropertyInfo displayMemberInfo = objType.GetProperty(this.DisplayMemberPath);
PropertyInfo selectedValueInfo = objType.GetProperty(this.SelectedValuePath);
PropertyInfo childValueInfo = objType.GetProperty(this.ChildMemberPath);
PropertyInfo parentValueInfo = objType.GetProperty(this.ParentMemberPath);

//--当前要显示的文本
string displayText = displayMemberInfo.GetValue(item, null).ToString();
//--当前选择的值
string selectedValue = selectedValueInfo.GetValue(item, null).ToString();
//---子级绑定的值
string childValue = childValueInfo.GetValue(item, null).ToString();
//--父级绑定的值
string parentValue = parentValueInfo.GetValue(item, null).ToString();

if (string.IsNullOrEmpty(childValue) || string.IsNullOrEmpty(parentValue))
{
return;
}
if (treeviewitem.Tag.ToString() == parentValue)
{
TreeViewItem myitem = new TreeViewItem();
myitem.Header = displayText;
myitem.Tag = selectedValue;

treeviewitem.Items.Add(myitem);

this.LoadItems(myitem, ItemsSource);
}
}
}
}
#endregion

/// <summary>
/// TreeView的选择事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void tvList_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs<object> e)
{
if (tvList.Items.Count > 0)
{
this.SelectedItem = tvList.SelectedItem;

if (string.IsNullOrEmpty(this.DisplayMemberPath) || string.IsNullOrEmpty(this.SelectedValuePath))
{
MessageBox.Show("此控件必须设置【DisplayMemberPath】和【SelectedValuePath】属性的值");
return;
}

Type objType = null;
PropertyInfo displayMemberInfo = null;
PropertyInfo selectedValueInfo = null;

foreach (var item in ItemsSource)
{
//获取实体的类型
objType = item.GetType();
//--用反射的方式 获得属性对应的值
displayMemberInfo = objType.GetProperty(this.DisplayMemberPath);
selectedValueInfo = objType.GetProperty(this.SelectedValuePath);

break;
}

TreeViewItem treeviewitem = tvList.SelectedItem as TreeViewItem;

//--当前要显示的文本
string displayText = treeviewitem.Header.ToString();
//--当前选择的值
this.SelectedValue = treeviewitem.Tag.ToString();

cbItemDisplay.Content = displayText;//设置ComboBox要显示的文本

//设置当前选择的项
foreach (var item in ItemsSource)
{
string selvalue = selectedValueInfo.GetValue(item, null).ToString();
if (!string.IsNullOrEmpty(selvalue))
{
if (treeviewitem.Tag.ToString() == selvalue)
{
this.SelectedItem = item; ;
}
}
}
}
}

private void cbMain_DropDownOpened(object sender, EventArgs e)
{
//--打开时 隐藏要显示的项
cbItemDisplay.Visibility = System.Windows.Visibility.Collapsed;
cbItemTreeView.Visibility = System.Windows.Visibility.Visible;
}

private void cbMain_DropDownClosed(object sender, EventArgs e)
{
//--关闭时,使显示的项可见
cbItemDisplay.Visibility = System.Windows.Visibility.Visible;
cbItemTreeView.Visibility = System.Windows.Visibility.Collapsed;

cbMain.SelectedItem = cbItemDisplay;//设置当前的选中项为显示项
}

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: