ToggleSwitch Winforms 控件
一个比标准复选框更能以有趣方式展示开/关值的 ToggleSwitch
引言
所以,我再次发布一篇关于自定义绘制的 Winforms 控件的文章。我想我应该把我的个人资料名称改成 “控件狂”…… 但管他呢:我喜欢编程自定义控件!对此无能为力。
这次,我需要一个 ToggleSwitch
或 ToggleButton
——一种比标准复选框更能以有趣方式显示二进制开/关选中/未选中状态的东西。像往常一样,我开始查看现有的控件,因为谁想花很多时间重新发明已经被发明过的东西呢???我通常发生的事情这次也发生了:我发现了一些本可以很棒的现有控件,但它们总有些方面让我不满意。我能找到的最好的(而且看起来也很棒)是 IKalai 的这个(当然是在 Code Project 上)。但 Ikalai 的控件有一些问题。最重要的是它不允许你随意改变控件的大小,而我无法将其调整到我的应用程序所需的尺寸…… :-( 我真的不明白他为什么要在他的控件上施加如此奇怪的限制!
我还发现了 这个,它看起来甚至更好——但可惜,它是为 WPF/Silverlight 构建的,所以我不能使用它。
所以我做了我经常做的事情:我开始自己编写控件。而且像往常一样,我做得太过火了,使其比我真正需要的要高级得多。而不是仅仅制作一个看起来和行为符合我期望的控件,我受到了以上两篇文章的启发,制作了一个可以呈现出很多不同外观的控件。最后,我得到了十种不同的样式,外加进一步自定义这些样式的可能性——并且可以创建自己的渲染器来添加更多样式,如果你有这个需要的话。
这些文章不仅启发了我,我必须承认我甚至从它们那里偷了一些想法…… 但代码是 100% 我自己的!
最后——在完成控件后——我有了完全不同的想法。所以我甚至不确定我是否会在我最初创建它的应用程序中使用我的 ToggleSwitch
。但无论如何,它在这里,供大家使用。
控件功能概览
1. 基本控件特性
控件当然是双缓冲的,以最大限度地减少闪烁。它还派生自 Control
类,因此同时支持 Anchor
和 Dock
属性。
2. 不同样式
我从 IKalai 的控件中借鉴了两种样式,从 WPF 控件中借鉴了七种。样式只需通过设置 Style
属性为您想要的样式即可更改。
3. 图片和文本支持
你可以根据喜好自定义控件。文本或图像可以插入到控件的每一侧(如果所选的渲染器支持)。你只能拥有文本或图像。如果你设置了图像属性,它将具有优先权,而文本属性将不会被使用。
你还可以在按钮本身插入图像(同样,如果所选的渲染器支持)。我没有为滑块按钮实现文本选项,因为我认为按钮上能容纳的文本太小了,毫无用处。
4. 其他炫酷属性
-
AllowUserChange
- 有时你可能不希望用户能够更改控件的值,但你也不想禁用它。如果将AllowUserChange = false
,用户将无法更改值,但你仍然可以在代码中更改它。 -
AnimationInterval
、AnimationStep
&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
事件,以便更轻松地自定义渲染器属性 - 新增:添加了
Style
和Renderer
:PlainAndSimple
- 更新:演示应用已更新以支持新功能
版本 1.0 (2015-09-11)
- 首次发布