65.9K
CodeProject 正在变化。 阅读更多。
Home

Easy ToolStrip - 让您的UserControl显示超出容器/窗体限制 (C# 和 VB.NET)

starIconstarIconstarIconstarIconstarIcon

5.00/5 (17投票s)

2016 年 8 月 3 日

CPOL

4分钟阅读

viewsIcon

25293

downloadIcon

2317

实现 ToolStripControlHost 和 ToolStripDropDown 类最简单的方法,在 UserControl 中,可以以很少的代码行,显示一个超出其父容器和父窗体限制的容器/控件。让我们化繁为简...

引言

当我(第一次)尝试以实际方式理解如何显示一个 UserControl **超出其限制** 的任何潜在父容器和父窗体时,我遇到了几个例子。大多数都很好,有些具有惊人的样式和视觉效果,然而所有这些都很复杂,纠缠不清,有时依赖于 UserControl 本身之外的操作。

由于我是一个简单的编码爱好者,本文的目的是展示如何通过在代码的三个不同的“关键部分”中添加 **非常少的代码行** 来将此技术应用于“下拉”UserControl。

  • 关键部分 1 - 变量定义
  • 关键部分 2 - UserControl 加载
  • 关键部分 3 - “下拉”操作控制器事件

此技术可应用于容器(如 Panel、GroupBox、TabControl 等)或控件(如 ListView、ListBox、TreeView、DataGridView 等)。

Using the Code

在此示例中,我们将构建一种下拉列表组合框(称为 CbBox),它由三个控件组成

  1. 一个标签(称为 LBox),用于显示选定的项目。
  2. 一个按钮(称为 bDrop),用于打开/显示或关闭/隐藏项目列表。
  3. 一个ListView(称为 _List),无标题,用于存储可选项。

标签按钮由设计器创建,是 UserControl 的可见且可调整大小的部分。

ListView 声明为实例变量,在 UserControl 加载时(仅在运行时)进行设置(只有一个列)。

关键部分 1 - 变量定义

只需定义 3 个变量

  1. _ListListView 类),用于存储数据项列表。在 VB.NET 中,是 Friend WithEvents,以便处理 ListView 事件 ItemSelectionChanged
  2. tsHostToolStripControlHost 类),用于托管控件(_List)。
  3. tsDropToolStripDropDown 类),用于显示托管控件(_List)中存储的数据项列表。
    // Instance variables
    private ListView _List;
    private ToolStripControlHost tsHost;
    private ToolStripDropDown tsDrop = new ToolStripDropDown();
    ' Instance variables
    Friend WithEvents _List As ListView
    Private tsHost As ToolStripControlHost
    Private tsDrop As ToolStripDropDown = New ToolStripDropDown

关键部分 2 - UserControl 加载

在 UserControl 的 Load 事件 中,但仅在运行时

  1. 使用适当的 属性 设置 ListView,无标题,只有一个列(在本例中)。
  2. 在 C# 中,添加 ListView 的 ItemSelectionChanged 事件处理程序
  3. ListView 附加到 ToolStripControlHost
    private void CbBox_Load(object sender, System.EventArgs e)
    {
        if (this.DesignMode == false)   // Only at Runtime
        {
            _List = new ListView();
            _List.View = View.Details;
            _List.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            _List.MultiSelect = false;
            _List.FullRowSelect = true;
            _List.HideSelection = false;
            _List.HeaderStyle = ColumnHeaderStyle.None;
            _List.GridLines = true;
            _List.Columns.Add(new ColumnHeader());
            _List.Columns[0].Width = this.Width - 21;
            //
            // Add the ItemSelectionChanged EventHandler
            _List.ItemSelectionChanged += _List_ItemSelectionChanged;
            //
            // Attach the ListView to the ToolStripControlHost
            tsHost = new ToolStripControlHost(_List);
            //
        }
    }
    Private Sub CbBox_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        If Me.DesignMode = False Then   ' Only at Runtime
            _List = New ListView
            _List.View = View.Details
            _List.BorderStyle = Windows.Forms.BorderStyle.FixedSingle
            _List.MultiSelect = False
            _List.FullRowSelect = True
            _List.HideSelection = False
            _List.HeaderStyle = ColumnHeaderStyle.None
            _List.GridLines = True
            _List.Columns.Add(New ColumnHeader)
            _List.Columns(0).Width = Me.Width - 21
            '
            ' Attach the ListView to the ToolStripControlHost
            tsHost = New ToolStripControlHost(_List)
            '
        End If
    End Sub

关键部分 3 - “下拉”操作控制器事件

按钮(或标签)的 Click 事件

  • 如果 _IsOpen 为 false,则显示 ToolStripDropDown
    1. 调整 ListView 的大小
      • 宽度 等于 UserControl 的宽度。
      • 高度 是预定义的 _MaxItemsDisp 与总数据项数之间的最小行数(如果没有数据项则为 1),
        乘以 17(每行 16 像素加上网格线 1 像素)再加上最后的 1 像素行。
    2. 防止显示不必要的行(边距、内边距)。
    3. ToolStripControlHost(它托管ListView)获取要由 ToolStripDropDown 显示的项。
    4. 显示 ToolStripDropDown,相对于 UserControl 的可见部分(标签和按钮),在指定的左上角位置(水平、垂直)。
  • 如果 _IsOpen 为 true,则隐藏 ToolStripDropDown
    private void bDrop_Click(object sender, EventArgs e)
    {
        // Shows or Hides the List, depending on _IsOpen
        // _IsOpen: True->tsDrop is shown, False->tsDrop is hidden
        if (_IsOpen == false)   // If hidden, show it
        {
            _List.Size = new Size(this.Width, Math.Min(_MaxItemsDisp, Math.Max(_List.Items.Count, 1)) * 17 + 1);
            if (tsHost != null)
            {
                tsHost.Margin = new Padding(0);
                tsDrop.Padding = new Padding(0);
                tsDrop.Items.Add(tsHost);
                tsDrop.Show(this, new Point(-1, this.Height - 2));
            }
        }
        else                    // If shown, hide it
        {
            tsDrop.Hide();
        }
        _IsOpen = !_IsOpen;     // Invert value
        bDrop.Focus();
    }
    Private Sub bDrop_Click(sender As Object, e As EventArgs) Handles bDrop.Click, LBox.Click
        ' Shows or Hides the List, depending on _IsOpen
        ' _IsOpen: True->tsDrop is shown, False->tsDrop is hidden
        If _IsOpen = False Then ' If hidden, show it
            _List.Size = New Size(Me.Width, Math.Min(_MaxItemsDisp, Math.Max(_List.Items.Count, 1)) * 17 + 1)
            If tsHost IsNot Nothing Then
                tsHost.Margin = New Padding(0)
                tsDrop.Padding = New Padding(0)
                tsDrop.Items.Add(tsHost)
                tsDrop.Show(Me, New Point(-1, Me.Height - 2))
            End If
        Else                    ' If shown, hide it
            tsDrop.Hide()
        End If
        _IsOpen = Not (_IsOpen) ' Invert value
        bDrop.Focus()
    End Sub

其他一些功能

UserControl 实际上非常简单。但是,除了上面显示的 3 个关键部分之外,还有一些其他代码片段

● ListView 的 ItemSelectionChanged 事件

ToolStripDropDown **显示**时,需要此事件来

  • 将选定的项目保存到变量 Item
  • 隐藏 ToolStripDropDown
  • 如果项目确实发生了更改
    • 将用户的选择复制到 UserControl 的标签控件
    • 触发 UserControl 的 SelectedItemChanged 事件
    private void _List_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
    {
        string Item = e.Item.Text;
        tsDrop.Hide();
        _IsOpen = false;
        if (LBox.Text != Item)
        {
            LBox.Text = Item;
            if (SelectedItemChanged != null)
            {
                SelectedItemChanged(Item);
            }
        }
    }
    Private Sub _List_ItemSelectionChanged(sender As Object, e As ListViewItemSelectionChangedEventArgs) _
                Handles _List.ItemSelectionChanged
        Dim Item As String = e.Item.Text
        tsDrop.Hide()
        _IsOpen = False
        If LBox.Text <> Item Then
            LBox.Text = Item
            RaiseEvent SelectedItemChanged(Item)
        End If
    End Sub

● UserControl 的 Resize 事件

当 UserControl 调整大小时,高度 不能小于 15,否则文本将被截断。

    private void CbBox_Resize(object sender, System.EventArgs e)
    {
        if (this.Height < 15)
        {
            this.Height = 15;
        }
    }
    Private Sub CbBox_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
        If Me.Height < 15 Then
            Me.Height = 15
        End If
    End Sub

宽度 调整大小时,按钮宽度不受影响(19 像素)。但当高度减小或增大时,按钮高度会相应改变

(高度 = 15 像素)

(高度 = 29 像素)

MouseHoverMouseLeave 事件

只是一个非常简单的视觉效果。当鼠标悬停在按钮控件上时,鼠标指针和按钮的背景颜色会发生变化

    private void bDrop_MouseHover(object sender, EventArgs e)
    {
        this.Cursor = Cursors.Hand;
        bDrop.BackColor = Color.Orange;
    }

    private void bDrop_MouseLeave(object sender, EventArgs e)
    {
        this.Cursor = Cursors.Default;
        bDrop.BackColor = Color.Lavender;
    }
    Private Sub bDrop_MouseHover(sender As Object, e As EventArgs) Handles bDrop.MouseHover
        Me.Cursor = Cursors.Hand
        sender.BackColor = Color.Orange
    End Sub

    Private Sub bDrop_MouseLeave(sender As Object, e As EventArgs) Handles bDrop.MouseLeave
        Me.Cursor = Cursors.Default
        sender.BackColor = Color.Lavender
    End Sub

● 属性

一些属性用于添加一些功能...

  • BackColor - (读/写)获取或设置 UserControl 的背景颜色
  • ForeColor - (读/写)获取或设置 UserControl 的前景色
  • MaxItemsDisp - (读/写)获取或设置要显示的行数
  • Text - (读/写)获取或设置 UserControl 的文本(标签控件)
  • Count - (只读)获取 ListView 的 ItemCollection 中的总项数
    public override Color BackColor
    {
        get { return LBox.BackColor; }
        set { LBox.BackColor = value; }
    }

    public override Color ForeColor
    {
        get { return LBox.ForeColor; }
        set { LBox.ForeColor = value; }
    }

    public int MaxItemsDisp
    {
        get { return _MaxItemsDisp; }
        set { _MaxItemsDisp = value; }
    }

    public override string Text
    {
        get { return LBox.Text; }
        set { LBox.Text = value; }
    }

    public int Count
    {
        get { return _List == null ? 0 : _List.Items.Count; }
    }
    Public Overrides Property BackColor As Color
        Get
            Return LBox.BackColor
        End Get
        Set(value As Color)
            LBox.BackColor = value
        End Set
    End Property

    Public Overrides Property ForeColor As Color
        Get
            Return LBox.ForeColor
        End Get
        Set(value As Color)
            LBox.ForeColor = value
        End Set
    End Property

    Public Property MaxItemsDisp() As Integer
        Get
            Return _MaxItemsDisp
        End Get
        Set(ByVal value As Integer)
            _MaxItemsDisp = value
        End Set
    End Property

    Public Overrides Property Text() As String
        Get
            Return LBox.Text
        End Get
        Set(ByVal value As String)
            LBox.Text = value
        End Set
    End Property

    Public ReadOnly Property Count() As Integer
        Get
            Return _List.Items.Count
        End Get
    End Property

● 方法

只需要一个方法

  • AddRow - 将字符串添加到ListViewItemCollection
    public void AddRow(string NewItem)
    {
        _List.Items.Add(NewItem);
    }
    Public Sub AddRow(ByRef NewItem As String)
        _List.Items.Add(NewItem)
    End Sub

● 事件

只有一个事件

  • SelectedItemChanged - 当 ListViewItemSelectionChanged 事件发生并且选定的项目确实发生更改时触发。
    public event SelectedItemChangedEventHandler SelectedItemChanged;
    public delegate void SelectedItemChangedEventHandler(string Item);
    Public Event SelectedItemChanged(Item As String)

演示项目

是一个简单的 Windows Forms 应用程序,可以在其中测试 UserControl 的所有功能。

UserControl DLL 位于 ...\bin\Debug\CbBox.dll

尽管我更喜欢 **VB.NET**,因为它简单易读(括号和分号很麻烦),
但我不得不承认 **C#** 的性能要高得多……DLL 文件大小

  • VB.NET 版本为 28 KB
  • C# 版本为 12 KB

  • 项目:每个组只能添加一次。
  • 其他播放器:输入并添加您想要的任何内容。
  • 要**设置属性**,请先点击白色框,然后输入或选择所需的值。颜色将显示一个颜色对话框。
  • 事件:每当选定的项目更改时,都会显示一条消息

历史

2016 年 8 月 3 日 - 首次发布。

© . All rights reserved.