创建可折叠控件的详细指南

用户界面设计中,经常需要在有限的空间内展示尽可能多的信息。为了满足这一需求,可折叠控件成为了一个理想的选择。本文将详细介绍如何使用C#创建一个垂直折叠的控件,以便用户可以在不滚动的情况下查看更多信息。

阅读前的准备

本指南将逐步指导完成创建可折叠控件的过程。在阅读过程中,将看到一些重复的函数和属性声明,其中新的更改将以粗体标记,而新的声明则以正常字体显示。

步骤1:绘制组框和图像

首先,将在组框的左上角绘制一个图像。需要声明一些变量,以确保控件最初是展开的,并定义图像矩形的边界。

private bool _iscollapsed = false; private Rectangle _buttonrect = new Rectangle(0, 14, 11, 11); public bool IsCollapsed { get { return _iscollapsed; } } private Rectangle ButtonRect { get { return _buttonrect; } }

接下来,需要创建一个新的函数来绘制组框。首先重新定位矩形,以便图像位于左侧线的中间。然后使用GroupBoxRenderer.DrawGroupBox函数绘制组框。

void DrawGroupBox(Graphics g) { Rectangle bounds = new Rectangle(ClientRectangle.X + 4, ClientRectangle.Y + 6, ClientRectangle.Width - 4, ClientRectangle.Height - 6); GroupBoxRenderer.DrawGroupBox(g, bounds, Enabled ? GroupBoxState.Normal : GroupBoxState.Disabled); }

还需要一个函数来绘制图像。

private void DrawButton(Graphics g) { if (IsCollapsed) g.DrawImage(Properties.Resources.plus, ButtonRect); else g.DrawImage(Properties.Resources.minusver, ButtonRect); }

在Paint函数中调用这些函数。

protected override void OnPaint(PaintEventArgs pe) { DrawGroupBox(pe.Graphics); DrawButton(pe.Graphics); }

完成这一步后,将看到初步的结果。

步骤2:添加垂直文本

在这一步中,将向组框添加垂直文本。需要定义一个StringFormat变量,并将文本方向设置为垂直。同时,定义一个SolidBrush,并在第一次调用时创建新的实例,然后重复使用并在结束时释放。

private StringFormat format = new StringFormat(StringFormatFlags.DirectionVertical); private SolidBrush _drawBrush = null; private SolidBrush DrawBrush { get { if (_drawBrush == null) return _drawBrush = new SolidBrush(Color.FromArgb(0, 70, 213)); else return _drawBrush; } }

在DrawGroupBox函数中计算字符串宽度,并调用DrawString函数在框的左侧线绘制文本。

void DrawGroupBox(Graphics g) { Rectangle bounds = new Rectangle(ClientRectangle.X + 4, ClientRectangle.Y + 6, ClientRectangle.Width - 4, ClientRectangle.Height - 6); GroupBoxRenderer.DrawGroupBox(g, bounds, Enabled ? GroupBoxState.Normal : GroupBoxState.Disabled); StringFormat sf = new StringFormat(); int i_textPos = (bounds.X + 8) + ButtonRect.Width + 2; int i_textSize = (int)g.MeasureString(Text, this.Font).Width; i_textSize = i_textSize < 1 ? 1 : i_textSize; int i_endPos = i_textPos + i_textSize + 1; g.DrawString(Text, this.Font, DrawBrush, ButtonRect.X - 4, ButtonRect.Y + 15, format); }

完成这一步后,将看到添加了垂直文本的结果。

步骤3:实现可折叠功能

在这一步中,将完成两项任务:(1) 使图像具有交互性,即像按钮一样工作;(2) 使组框成为一个可折叠的盒子。

private int _actualwidth = 0; private int _currentwidth = 0; private int _collapsewidth = 20; private int CollapseWidth { get { return _collapsewidth; } } private int ActualWidth { get { return _actualwidth; } set { _actualwidth = value; } } private int CurrentWidth { get { return _currentwidth; } set { _currentwidth = value; } } public bool IsCollapsed { get { return _iscollapsed; } set { _iscollapsed = value; if (!value) { Width = ActualWidth; } else Width = CollapseWidth; Invalidate(); } } protected override void OnPaint(PaintEventArgs pe) { if (ActualWidth == 0) ActualWidth = Width; DrawGroupBox(pe.Graphics); DrawButton(pe.Graphics); }

重写OnMouseUp函数,以捕获是否在图像内执行了点击操作,如果是,则调用CollapsedChange函数并切换其当前状态。

private void CollapsedChanged() { IsCollapsed = !IsCollapsed; } protected override void OnMouseUp(MouseEventArgs e) { if (ButtonRect.Contains(e.Location)) { CollapsedChanged(); } base.OnMouseUp(e); }

完成这一步后,将看到可折叠功能的结果。

步骤4:美化控件

在这一步中,将对控件进行美化。如果看到文本下方有一条线,看起来不太美观,可以通过重写OnResize函数并调整其实际宽度来解决这个问题,这在控件大小发生变化时非常有用。

void DrawGroupBox(Graphics g) { Rectangle bounds = new Rectangle(ClientRectangle.X + 4, ClientRectangle.Y + 6, ClientRectangle.Width - 4, ClientRectangle.Height - 6); GroupBoxRenderer.DrawGroupBox(g, bounds, Enabled ? GroupBoxState.Normal : GroupBoxState.Disabled); StringFormat sf = new StringFormat(); int i_textPos = (bounds.X + 8) + ButtonRect.Width + 2; int i_textSize = (int)g.MeasureString(Text, this.Font).Width; i_textSize = i_textSize < 1 ? 1 : i_textSize; int i_endPos = i_textPos + i_textSize + 1; g.DrawLine(SystemPens.Control, ButtonRect.X + 4, ButtonRect.Y + 15, ButtonRect.X + 4, i_endPos); g.DrawString(Text, this.Font, DrawBrush, ButtonRect.X - 4, ButtonRect.Y + 15, format); } protected override void OnResize(EventArgs e) { if (ActualWidth == 0) ActualWidth = Width; base.OnResize(e); }

完成这一步后,控件将更加美观。

步骤5:添加事件支持

在这一步中,将添加事件支持。当折叠更改事件触发时,可以在父窗体中执行操作。

public delegate void CollapseChangeEventHandler(object sender); public event CollapseChangeEventHandler OnCollapsedChanged; private void CollapsedChanged() { IsCollapsed = !IsCollapsed; if (OnCollapsedChanged != null) OnCollapsedChanged(this); }

完成这一步后,控件将能够响应折叠更改事件。

步骤6:解决可见性问题

现在控件几乎已经准备好了,但当折叠盒子时,左对齐的控件仍然可见。这个问题可以通过设置此控件内所有控件的可见属性来解决,但对于那些最初隐藏的控件,这种方法也会使它们显示出来。因此,需要维护控件的可见状态。

private List _visiblectrls = new List(); public bool IsCollapsed { get { return _iscollapsed; } set { _iscollapsed = value; if (!value) { Width = ActualWidth; } else Width = CollapseWidth; foreach (Control c in _visiblectrls) { c.Visible = !value; } Invalidate(); } } protected override void OnLayout(LayoutEventArgs levent) { if (_visiblectrls.Count == 0) { foreach (Control c in Controls) { if (c.Visible) _visiblectrls.Add(c); } } base.OnLayout(levent); }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485