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





5.00/5 (17投票s)
实现 ToolStripControlHost 和 ToolStripDropDown 类最简单的方法,在 UserControl 中,可以以很少的代码行,显示一个超出其父容器和父窗体限制的容器/控件。让我们化繁为简...
引言
当我(第一次)尝试以实际方式理解如何显示一个 UserControl **超出其限制** 的任何潜在父容器和父窗体时,我遇到了几个例子。大多数都很好,有些具有惊人的样式和视觉效果,然而所有这些都很复杂,纠缠不清,有时依赖于 UserControl 本身之外的操作。
由于我是一个简单的编码爱好者,本文的目的是展示如何通过在代码的三个不同的“关键部分”中添加 **非常少的代码行** 来将此技术应用于“下拉”UserControl。
- 关键部分 1 - 变量定义
- 关键部分 2 - UserControl 加载
- 关键部分 3 - “下拉”操作控制器事件
此技术可应用于容器(如 Panel、GroupBox、TabControl 等)或控件(如 ListView、ListBox、TreeView、DataGridView 等)。
Using the Code
在此示例中,我们将构建一种下拉列表组合框(称为 CbBox
),它由三个控件组成
- 一个标签(称为
LBox
),用于显示选定的项目。 - 一个按钮(称为
bDrop
),用于打开/显示或关闭/隐藏项目列表。 - 一个ListView(称为
_List
),无标题,用于存储可选项。
● 标签和按钮由设计器创建,是 UserControl 的可见且可调整大小的部分。
● ListView 声明为实例变量,在 UserControl 加载时(仅在运行时)进行设置(只有一个列)。
关键部分 1 - 变量定义
只需定义 3 个变量
_List
(ListView 类),用于存储数据项列表。在 VB.NET 中,是Friend WithEvents
,以便处理 ListView 事件ItemSelectionChanged
。tsHost
(ToolStripControlHost 类),用于托管控件(_List
)。tsDrop
(ToolStripDropDown 类),用于显示托管控件(_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 事件
中,但仅在运行时
- 使用适当的
属性
设置 ListView,无标题,只有一个列(在本例中)。 - 在 C# 中,添加 ListView 的
ItemSelectionChanged
事件处理程序 - 将 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- 调整 ListView 的大小
宽度
等于 UserControl 的宽度。高度
是预定义的_MaxItemsDisp
与总数据项数之间的最小行数(如果没有数据项则为 1),
乘以 17(每行 16 像素加上网格线 1 像素)再加上最后的 1 像素行。
- 防止显示不必要的行(边距、内边距)。
- 从ToolStripControlHost(它托管ListView)获取要由 ToolStripDropDown 显示的项。
- 显示 ToolStripDropDown,相对于 UserControl 的可见部分(标签和按钮),在指定的左上角位置(水平、垂直)。
- 调整 ListView 的大小
- 如果
_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 像素)
● MouseHover
和 MouseLeave
事件
只是一个非常简单的视觉效果。当鼠标悬停在按钮控件上时,鼠标指针和按钮的背景颜色会发生变化
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
- 将字符串添加到ListView 的ItemCollection
。
public void AddRow(string NewItem)
{
_List.Items.Add(NewItem);
}
Public Sub AddRow(ByRef NewItem As String)
_List.Items.Add(NewItem)
End Sub
● 事件
只有一个事件
SelectedItemChanged
- 当 ListView 的ItemSelectionChanged
事件发生并且选定的项目确实发生更改时触发。
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 日 - 首次发布。