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

又一个 Vista 风格的 CommandLink

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (35投票s)

2008年7月17日

CPOL

4分钟阅读

viewsIcon

103759

downloadIcon

1994

一个与操作系统无关的 CommandLink 控件。

引言

有很多很棒的 Vista 风格控件是用 .NET 编写的。所以这是又一个,一个命令链接按钮。我喜欢从头开始创建自定义控件,而不是依赖操作系统绘图库。因此,我们的 CommandLink 完全用 C# 代码绘制,使其与旧版本的 Windows 兼容。

CommandLink 的目标

当我着手编写这个控件时,我决定我想要一个具有 Vista 风格感觉的 CommandLink,但又不像默认 CommandLinks 那样精确复制。因此,我写了一个简单的目标列表,列出了要包含的元素

  • 同一按钮内有两种不同的字体大小,即标题文本和描述文本。
  • 左侧有一个图像/图标,与 Vista 的 CommandLink 不同,它可以垂直对齐到顶部、中间或底部。
  • 默认情况下是混合的扁平外观,鼠标悬停时是渐变外观。
  • 行为像一个按钮。

圆角矩形

在绘制实际控件之前,首先我们需要一个绘制圆角矩形的函数。由于按钮需要勾勒和填充圆角矩形,因此编写一个返回 GraphicsPath 的函数是最简单的

private static GraphicsPath RoundedRect(int width, int  height, int radius)
{
      RectangleF  baseRect = new RectangleF(0, 0, width, height);
      float diameter =  radius * 2.0f;
      SizeF sizeF = new SizeF(diameter,  diameter);
      RectangleF arc = new  RectangleF(baseRect.Location, sizeF);
      GraphicsPath path  = new GraphicsPath();

      // top left arc
      path.AddArc(arc,  180, 90);
      // top right arc 
      arc.X =  baseRect.Right - diameter;
      path.AddArc(arc,  270, 90);
      // bottom right  arc 
      arc.Y =  baseRect.Bottom - diameter;
      path.AddArc(arc,  0, 90);
      // bottom left arc
      arc.X =  baseRect.Left;
      path.AddArc(arc,  90, 90);

      path.CloseFigure();
      return path;
}

绘制元素

因此,让我们分解一下 CommandLink 的视觉元素。唯一复杂的两种状态是悬停状态和按下状态。

悬停

hover-1.png

使按钮弹出部分是一个简单的白色渐变,占按钮高度的三分之四。由于 LinearGradientBrush 的工作方式,有时如果渐变绘制区域比所需区域高 1 像素,渐变就会重新开始,导致控件中间出现一条丑陋的白色线。为了解决这个问题,我们在声明 LinearGradientBrush 后添加以下一行

WrapMode.TileFlipX

hover-2.png

接下来是轮廓。它是使用上述函数生成的 3 像素半径的圆角矩形。颜色可以是 SystemColors.ColorDark,或者如果你喜欢固定颜色,(189, 189, 189) 效果很好。

hover-3.png

然后,我们需要一个内部轮廓。这个半径将是 2 像素,并位于坐标 (1, 1)。颜色是略带透明的白色,alpha 值为 245。

我们将它们按顺序绘制,组合在一起,得到这样的效果

hover-all.png

向下

down-1.png

这次背景是实心的,同样,它可以是系统颜色 (ControlLight),或者 (234, 234, 234),如果你更喜欢固定颜色。

down-2.png

轮廓将与之前相同,只是颜色会更深,(167, 167, 167)

down-3.png

最后,内部轮廓的颜色也会变成深色(以产生阴影效果)。

最终的按下状态

down-all.png

高亮

用户应该能够分辨 CommandLink 何时被选中,即使是通过 Tab 键完成的。为了高亮显示选中的 CommandLink,我们只绘制一个内轮廓,颜色为 (192, 233, 243),这是一种浅蓝色。

前景 - 图像和文本

前景元素对于按钮的任何状态都将是相同的。绘制文本和图像实际上没有什么特别之处。描述文本将始终比标题文本小三号。字体可以更改,但默认字体是 Tahoma。为了使标题和描述文本的总尺寸居中,可以使用

SizeF headerLayout = g.MeasureString(headerText, this.Font);
SizeF descriptLayout = g.MeasureString(descriptionText,  descriptFont);

//Merge the two sizes into one big rectangle
Rectangle totalRect = new Rectangle(0, 0, 
                                   (int)Math.Max(headerLayout.Width,  
                                   descriptLayout.Width), 
                                   (int)(headerLayout.Height + 
                                    descriptLayout.Height) - 4);

另外,这是控件在禁用时会发生变化的部分。文本只需更改颜色。然而,图像需要转换为灰度(如果尚未完成)。

需要重写的事件

有几个事件需要重写才能使 CommandLink 表现得像我们想要的

  • OnPaint - 处理所有绘图方法;根据 CommandLink 的状态,执行相应的绘图例程。
  • OnClick - 由于用户控件不继承 Button 类,如果我们想能够指定 DialogResult,则需要在此时手动处理行为。
  • OnKeyPress - 如果 CommandLink 被 Tab 键选中并且用户按下 Enter 键,则执行 PerformClick
  • OnGotFocus/OnLostFocus - 刷新控件以绘制/移除浅蓝色高亮。
  • OnMouse[…] - 所有 OnMouse 事件都只是更改一个变量以反映 CommandLink 的当前状态,并使控件重绘自身。
  • OnEnabledChanged - 设置正确的状态并重绘 CommandLink。(注意,不幸的是,此事件在设计时不会被调用,但在运行时工作正常。)

结论和改进

最后,我们得到一个具有按钮基本功能但外观像 Vista 风格 CommandLink 的控件。实现旨在兼容旧版本的 Windows,因此可以进行一些可选的改进。例如,不支持 Vista 控件的渐变淡入淡出,目前图像必须在左侧。

© . All rights reserved.