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

ToggleSwitch Winforms 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.98/5 (76投票s)

2015年9月11日

CPOL

7分钟阅读

viewsIcon

175859

downloadIcon

22430

一个比标准复选框更能以有趣方式展示开/关值的 ToggleSwitch

引言

所以,我再次发布一篇关于自定义绘制的 Winforms 控件的文章。我想我应该把我的个人资料名称改成 “控件狂”…… 但管他呢:我喜欢编程自定义控件!对此无能为力。

这次,我需要一个 ToggleSwitchToggleButton——一种比标准复选框更能以有趣方式显示二进制开/关选中/未选中状态的东西。像往常一样,我开始查看现有的控件,因为谁想花很多时间重新发明已经被发明过的东西呢???我通常发生的事情这次也发生了:我发现了一些本可以很棒的现有控件,但它们总有些方面让我不满意。我能找到的最好的(而且看起来也很棒)是 IKalai 的这个(当然是在 Code Project 上)。但 Ikalai 的控件有一些问题。最重要的是它不允许你随意改变控件的大小,而我无法将其调整到我的应用程序所需的尺寸…… :-( 我真的不明白他为什么要在他的控件上施加如此奇怪的限制!

我还发现了 这个,它看起来甚至更好——但可惜,它是为 WPF/Silverlight 构建的,所以我不能使用它。

所以我做了我经常做的事情:我开始自己编写控件。而且像往常一样,我做得太过火了,使其比我真正需要的要高级得多。而不是仅仅制作一个看起来和行为符合我期望的控件,我受到了以上两篇文章的启发,制作了一个可以呈现出很多不同外观的控件。最后,我得到了十种不同的样式,外加进一步自定义这些样式的可能性——并且可以创建自己的渲染器来添加更多样式,如果你有这个需要的话。

这些文章不仅启发了我,我必须承认我甚至从它们那里偷了一些想法…… 但代码是 100% 我自己的!

最后——在完成控件后——我有了完全不同的想法。所以我甚至不确定我是否会在我最初创建它的应用程序中使用我的 ToggleSwitch。但无论如何,它在这里,供大家使用。

控件功能概览

1. 基本控件特性

控件当然是双缓冲的,以最大限度地减少闪烁。它还派生自 Control 类,因此同时支持 AnchorDock 属性。

2. 不同样式

我从 IKalai 的控件中借鉴了两种样式,从 WPF 控件中借鉴了七种。样式只需通过设置 Style 属性为您想要的样式即可更改。

3. 图片和文本支持

你可以根据喜好自定义控件。文本或图像可以插入到控件的每一侧(如果所选的渲染器支持)。你只能拥有文本或图像。如果你设置了图像属性,它将具有优先权,而文本属性将不会被使用。

你还可以在按钮本身插入图像(同样,如果所选的渲染器支持)。我没有为滑块按钮实现文本选项,因为我认为按钮上能容纳的文本太小了,毫无用处。

4. 其他炫酷属性

  • AllowUserChange - 有时你可能不希望用户能够更改控件的值,但你也不想禁用它。如果将 AllowUserChange = false,用户将无法更改值,但你仍然可以在代码中更改它。

  • AnimationIntervalAnimationStep & UseAnimation - 当滑块从一个状态移动到另一个状态时,它可以被动画化。当 UseAnimation = true 时,其他两个值决定按钮移动的速度。通常,它会以 AnimationInterval 设置的毫秒数为周期,以 AnimationStep 设置的像素数移动。如果你希望按钮立即改变状态,只需将 UseAnimation = false

  • GrayWhenDisabled - 决定在控件被禁用时是否以灰度显示,还是保留启用时的外观。

  • ThresholdPercentage - 决定你必须拖动按钮多远它才会吸附到另一侧。默认是 50%,所以如果你将滑块按钮拖动超过控件的一半,它将自动吸附到另一侧。该百分比始终从按钮当前所在的一侧计算。

  • ToggleOnButtonClick & ToggleOnSideClick - 用户当然可以随时拖动滑块按钮来改变开关的值。但是通过这些属性,你也可以决定控件是否应该在用户点击时切换。如果 ToggleOnButtonClick = true,点击滑块按钮将切换开关。如果 ToggleOnSideClick = true,你甚至可以点击按钮旁边的区域来切换开关。如果两者都为 true,点击控件的任何地方都会切换它;如果两者都为 false,点击控件将没有任何效果。

5. 可自定义的渲染器

每种样式都有自己的渲染器。一些基本属性(如图像属性)非常常见,可以直接在 ToggleSwitch 控件上找到。不过,并非所有渲染器都接受所有这些属性。但大多数都可以。其他属性,如颜色,我选择附加到特定的渲染器上。因为它们都以非常不同的方式绘制控件,所以很难在 ToggleSwitch 控件中创建适用于所有不同场景的通用颜色属性。

通过将颜色属性作为渲染器的一部分,可以比其他方式更进一步地自定义特定样式的外观。缺点是,要做到这一点,你必须创建一个渲染器的新实例,更改属性,然后将新渲染器分配给控件。但这并不难,并且演示程序确切地展示了如何做到这一点。

在控件的 1.1 版本中,我在 BeforeRendering 事件中传递了渲染器实例,以便可以直接设置属性而无需先创建新实例。

关注点

我最初为我的应用程序想要的外观是带拉丝金属旋钮的那种。我之前见过的所有带拉丝金属旋钮的控件都是这样做的:将 Photoshop 创建的图像文件嵌入到资源中,然后在控件表面绘制。我找到了一个 Photoshop 教程,教我如何创建这样的图像……

但这让我感到不安,也是我轻度自闭症的表现。嵌入文件并绘制它不如直接在控件上绘制“干净”。

即使有了 Photoshop 教程,我也真的不知道如何在 C# 中绘制它。我问了 Code Project 上的一些人,但没有得到太多帮助。Pete 告诉我我必须使用渐变画笔——我早就知道了,但我就是不知道该如何实现。所以我又 Google 了一下。我找到了很多关于使用 PathGradientBrush 填充一个圆形的例子。但所有这些例子都展示了如何创建一个从圆形内中心到外边界(或反之)的渐变。而我当然需要创建一个围绕圆形内部的渐变。

这并不容易,但终于,我找到了 这个例子,它或多或少地实现了我需要的功能。

所以我开始将金属旋钮的图像分成渐变扇形,然后逐个绘制它们。这奏效了。但奇怪的是,我发现如果我使用旋钮的实际中心作为画笔的中心来绘制所有渐变,我并没有得到预期的外观。为了获得正确的外观,我不得不稍微偏移每个画笔的中心。我不知道为什么,但我最终成功了,我想。

我的“手工绘制”拉丝金属旋钮可能看起来不如 Photoshop 的那么逼真,但我对结果还是相当满意。更重要的是,我不需要在控件库中包含资源就可以使其工作。

历史

版本 1.1 (2019-02-20)

  • 新增:添加了 BeforeRendering 事件,以便更轻松地自定义渲染器属性
  • 新增:添加了 StyleRendererPlainAndSimple
  • 更新:演示应用已更新以支持新功能

版本 1.0 (2015-09-11)

  • 首次发布
© . All rights reserved.