using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Drawing; namespace Core.StlMes.Client.SaleBase { public class TreeComboBox : ComboBox { #region 自定义成员变量 private TextBox m_TextBox; private TreeView m_TreeView; private Button m_DropdownButton; private int m_MaxDropDownItems = 8; //是否正在显示下拉列表 private bool b_Dropdown = false; //使能 private bool b_Enabled = true; //事件 public event EventHandler DropDown; public event EventHandler DropDownClosed; public event EventHandler EnableChanged; public event TreeViewCancelEventHandler BeforeExpand; public event TreeViewCancelEventHandler BeforeCollapse; public event TreeViewEventHandler AfterExpand; public event TreeViewEventHandler AfterCollapse; #endregion /// /// 构造函数 /// public TreeComboBox() { this.InitControls(); this.LayoutControls(); } #region 内部辅助方法 /// /// 创建并初始化所有控件,包括添加事件处理函数 /// private void InitControls() { //TextBox this.m_TextBox = new TextBox(); this.m_TextBox.KeyDown += new KeyEventHandler(m_TextBox_KeyDown); this.m_TextBox.Parent = this; this.m_TextBox.ReadOnly = true; //Button this.m_DropdownButton = new Button(); //Assembly asm = Assembly.GetExecutingAssembly(); //System.IO.Stream stream = asm.GetManifestResourceStream(asm.GetName().Name + ".BM_dropdown.bmp"); Bitmap bm = new Bitmap(this.GetType(), "BM_dropdown.bmp"); this.m_DropdownButton.Image = bm; this.m_DropdownButton.Width = 16; this.m_DropdownButton.Height = this.m_TextBox.Height-2; this.m_DropdownButton.Location = new Point(this.m_TextBox.Right-18, 1); this.m_DropdownButton.Click += new EventHandler(m_DropdownButton_Click); this.m_DropdownButton.TextChanged += new EventHandler(m_DropdownButton_TextChanged); this.m_DropdownButton.FlatStyle = FlatStyle.Flat; this.m_DropdownButton.Parent = this; this.m_DropdownButton.BringToFront(); //TreeView this.m_TreeView = new TreeView(); this.m_TreeView.Visible = false; this.m_TreeView.DoubleClick += new EventHandler(m_TreeView_DoubleClick); this.m_TreeView.KeyDown += new KeyEventHandler(m_TreeView_KeyDown); this.m_TreeView.LostFocus += new EventHandler(m_TreeView_LostFocus); this.m_TreeView.BeforeExpand += new TreeViewCancelEventHandler(m_TreeView_BeforeExpand); this.m_TreeView.BeforeCollapse += new TreeViewCancelEventHandler(TreeComboBox_BeforeCollapse); this.m_TreeView.AfterExpand += new TreeViewEventHandler(m_TreeView_AfterExpand); this.m_TreeView.AfterCollapse += new TreeViewEventHandler(TreeComboBox_AfterCollapse); this.m_TreeView.Location = new Point(0, 0); this.m_TreeView.Parent = null; this.LostFocus += new EventHandler(TreeComboBox_LostFocus); } /// /// 布局所有控件,让TextBox尺寸适应容器尺寸 /// private void LayoutControls() { this.m_TextBox.Width = this.Width; this.Height = this.m_TextBox.Height; this.m_DropdownButton.Left = this.m_TextBox.Right - 18; this.m_DropdownButton.Height = this.m_TextBox.Height - 2; this.m_TreeView.Width = this.Width * 2; this.m_TreeView.Height = (int)((this.Font.Height+3) * this.m_MaxDropDownItems); } /// /// 显示下拉列表 /// private void ShowDropDown() { if (this.Parent == null) return; // 智能计算显示的位置,尝试在下方显示,如果没有足够空间,则在上方显示 // 尝试在下方的位置(现在只是相对父窗口的相对位置) Point pos = new Point(this.Left, this.Bottom-1); // 把位置映射到顶层窗口,获取父窗口的屏幕坐标 Point parentPos = this.Parent.PointToScreen(this.Parent.Location); // 获取顶层窗口的屏幕坐标 Point topParentPos = this.TopLevelControl.PointToScreen(this.Parent.Location); // 把相对父窗口的位置变换为相对顶级窗口的位置,因为popup的父是顶级窗口 pos.Offset(parentPos.X - topParentPos.X, parentPos.Y - topParentPos.Y); // 检查是否有足够空间用于在label下方显示day picker if ((pos.Y + this.m_TreeView.Height) > this.TopLevelControl.ClientRectangle.Height) { // 没有足够的空间(超出了顶级窗口客户区),尝试在上方显示将Y方向,向上平移 pos.Y -= (this.Height + this.m_TreeView.Height); if (pos.Y < 0) { // 如果上方仍然没有空间显示,则显示在顶级窗口的底部 pos.Y = (this.TopLevelControl.ClientRectangle.Height -this.m_TreeView.Height); } } // 尝试停靠,如果右边超过顶级窗口的客户区,则将控件向左移动,并紧靠在顶级窗口右侧 if ((pos.X + this.m_TreeView.Width) > this.TopLevelControl.ClientRectangle.Width) pos.X = (this.TopLevelControl.ClientRectangle.Width - this.m_TreeView.Width); this.m_TreeView.Location = pos;// this.Parent.PointToScreen(pt); this.m_TreeView.Visible = true; this.m_TreeView.Parent = this.TopLevelControl; this.m_TreeView.BringToFront(); this.b_Dropdown = true; //raise event if (this.DropDown != null) this.DropDown(this, EventArgs.Empty); this.m_TreeView.Focus(); } /// /// 隐藏下拉列表 /// private void HideDropDown() { if (this.DropDownClosed != null) this.DropDownClosed(this,EventArgs.Empty); this.m_TreeView.Parent = null; this.m_TreeView.Visible = false; this.b_Dropdown = false; } #endregion #region 事件处理 - TextBox /// /// 在编辑框中按下按键 /// /// /// private void m_TextBox_KeyDown(object sender, KeyEventArgs e) { if (e.KeyCode == Keys.Enter) { if (this.b_Dropdown) this.HideDropDown(); else this.ShowDropDown(); } else if (e.KeyCode == Keys.Down) { this.ShowDropDown(); this.m_TreeView.Focus(); } } /// /// 在编辑框改变Text /// /// /// private void m_DropdownButton_TextChanged(object sender, EventArgs e) { throw new NotImplementedException(); } #endregion #region 事件处理 - TreeView /// /// 在下拉列表中选择了一个节点的事件处理! /// /// /// private void m_TreeView_KeyDown(object sender, KeyEventArgs e) { //如果按下回车表示要选中当前节点 if (e.KeyCode == Keys.Enter) { this.m_TreeView_DoubleClick(sender, EventArgs.Empty); } } /// /// 失去焦点时,如果不是被下拉按钮夺取的焦点,则隐藏它! /// /// /// void m_TreeView_LostFocus(object sender, EventArgs e) { if(!this.m_DropdownButton.Focused) this.HideDropDown(); } /// /// 在下拉列表中双击 /// /// /// private void m_TreeView_DoubleClick(object sender, EventArgs e) { TreeNode node = this.m_TreeView.SelectedNode; if (node != null) this.m_TextBox.Text = node.Text; if (this.b_Dropdown) { this.HideDropDown(); } } void TreeComboBox_AfterCollapse(object sender, TreeViewEventArgs e) { if (this.AfterCollapse != null) this.AfterCollapse(this, e); } void TreeComboBox_BeforeCollapse(object sender, TreeViewCancelEventArgs e) { if (this.BeforeCollapse != null) this.BeforeCollapse(this, e); } void m_TreeView_AfterExpand(object sender, TreeViewEventArgs e) { if (this.AfterExpand != null) this.AfterExpand(this,e); } void m_TreeView_BeforeExpand(object sender, TreeViewCancelEventArgs e) { if (this.BeforeExpand != null) this.BeforeExpand(this, e); } #endregion #region 事件处理 - Button private void m_DropdownButton_Click(object sender, EventArgs e) { //throw new Exception("The method or operation is not implemented."); if (this.b_Dropdown) this.HideDropDown(); else this.ShowDropDown(); } #endregion #region 事件处理 - 自身 /// /// 失去焦点 /// /// /// private void TreeComboBox_LostFocus(object sender, EventArgs e) { if (this.b_Dropdown) this.HideDropDown(); } /// /// 重设尺寸 /// /// protected override void OnResize(EventArgs e) { base.OnResize(e); this.LayoutControls(); } protected override void OnSizeChanged(EventArgs e) { base.OnSizeChanged(e); this.LayoutControls(); } #endregion #region 外部属性封装 /// /// 获取节点集合 /// public TreeNodeCollection Nodes { get { return this.m_TreeView.Nodes; } } /// /// 设置或者获取节点的图片列表 /// public ImageList ImageList { get { return this.m_TreeView.ImageList; } set { this.m_TreeView.ImageList = value; } } /// /// 重写enabled属性 /// public new bool Enabled { get { return this.b_Enabled; } set { if (this.b_Enabled != value) { this.b_Enabled = value; this.m_DropdownButton.Enabled = value; this.b_Enabled = value; //当灰掉时,隐藏下拉列表 if (!this.b_Enabled && this.b_Dropdown) this.HideDropDown(); if (this.EnableChanged != null) this.EnableChanged(this, EventArgs.Empty); } } } /// /// 字体 /// public override Font Font { get { return base.Font; } set { base.Font = value; this.m_TextBox.Font = value; this.m_TreeView.Font = value; //调整布局 this.LayoutControls(); } } /// /// 重写Text /// public override string Text { get { return this.m_TextBox.Text; } set { if (this.Text != value) { this.m_TextBox.Text = value; } } } /// /// 是否显示lines /// public bool ShowLines { get { return this.m_TreeView.ShowLines; } set { this.m_TreeView.ShowLines = value; } } /// /// 是否显示+ -按钮 /// public bool ShowPlusMinus { get { return this.m_TreeView.ShowPlusMinus; } set { this.m_TreeView.ShowPlusMinus = value; } } /// /// 是否显示root lines /// public bool ShowRootLines { get { return this.m_TreeView.ShowRootLines; } set { this.m_TreeView.ShowRootLines = value; } } /// /// 是否显示root lines /// public bool ShowNodeToolTips { get { return this.m_TreeView.ShowNodeToolTips; } set { this.m_TreeView.ShowNodeToolTips = value; } } /// /// 获取或者设置选中的节点! /// public TreeNode SelectedNode { get { return this.m_TreeView.SelectedNode; } set { this.m_TreeView.SelectedNode = value; if (value != null) this.Text = value.Text; } } public int MaxDropDownItems { get { return this.m_MaxDropDownItems; } set { if (this.m_MaxDropDownItems != value) { this.m_MaxDropDownItems = value; this.m_TreeView.Height = this.m_TextBox.Height * value; } } } #endregion } }