在编程的世界里,自定义控件是一种既有趣又具有挑战性的任务。作为一名热衷于编程的开发者,经常沉浸在创建各种自定义控件的过程中。最近,需要一个ToggleSwitch或ToggleButton,它能够以比标准复选框更有趣的方式显示二进制的On/Off或Checked/Unchecked状态。
在开始设计之前,通常会先查看现有的控件,因为没有人愿意花费大量时间重新发明轮子。然而,这次遇到的情况和往常一样:找到了一些本可以很好的控件,但它们在某些方面并没有完全满足需求。
找到了IKalai在Code Project上分享的一个控件,它的外观非常好看,但它不允许根据需要改变控件的大小,这让感到非常失望。不明白为什么他要给控件设置这样一个奇怪的限制。
还找到了另一个外观更好看的控件,但它是为WPF/Silverlight设计的,所以无法使用它。因此,决定像往常一样,开始编写自己的控件。
在设计过程中,不仅完全超越了需求,还受到了上述两篇文章的启发,制作了一个可以以多种不同方式呈现外观的控件。最终,得到了十种不同的样式,还可以进一步定制这些样式,并创建自己的渲染器以添加更多样式。
文章不仅给了灵感,还从中“窃取”了一些想法... 但代码100%是!
在完成控件后,突然有了一个完全不同的想法。所以甚至不确定是否会在创建它的应用程序中使用ToggleSwitch。但无论如何,把它放在这里,供大家使用。
控件当然是双缓冲的,以最小化闪烁。它还派生自Control类,因此支持Anchor和Dock属性。
从IKalai的控件中借鉴了两种样式,从WPF控件中借鉴了七种。通过简单地将Style属性设置为想要的样式,就可以更改样式。
可以根据需要自定义控件。如果所选渲染器支持,可以在控件的每一侧插入文本或图像。只能拥有文本或图像中的一个。如果设置了图像属性,它将优先使用,文本属性将不会被使用。
还可以在按钮本身中插入图像(如果所选渲染器支持)。没有为滑块按钮实现文本选项,因为判断是,能够适应按钮的文本将如此之小,以至于没有用处。
AllowUserChange - 可能存在不希望用户能够更改控件的值,但也不想禁用它的情况。如果设置AllowUserChange = false,用户将无法更改值,但仍然可以在代码后面更改它。
AnimationInterval, AnimationStep & UseAnimation - 当滑块从一个状态移动到另一个状态时,可以进行动画处理。当UseAnimation = true时,另外两个值决定了按钮移动的速度。通常,它以AnimationStep设置的像素数移动,每AnimationInterval设置的毫秒数移动一次。如果希望按钮立即更改状态,只需将UseAnimation设置为false。
GrayWhenDisabled - 确定当控件被禁用时,是将其以灰度绘制,还是保留启用时的外观。
ThresholdPercentage - 确定必须将按钮拖动多远,它才会自动跳转到另一侧。默认值为50%,因此如果将滑块按钮拖动超过控件的一半,它将自动跳转到另一侧。百分比始终从按钮当前所在的一侧计算。
ToggleOnButtonClick & ToggleOnSideClick - 用户当然总是可以通过拖动滑块按钮来更改开关的值。但是使用这些属性,还可以决定如果用户点击控件,是否应该切换。如果ToggleOnButtonClick = true,则点击滑块按钮将切换开关。如果ToggleOnSideClick = true,则甚至可以点击按钮旁边的区域并使开关切换。如果两者都是true,则点击控件的任何地方都会切换它,如果两者都是false,则点击控件将没有任何效果。
每种样式都有自己的渲染器。一些基本属性(如图像属性)非常通用,可以直接在ToggleSwitch控件上找到。并非所有渲染器都接受所有这些属性。但是大多数都接受。其他属性,如颜色,选择将其附加到特定的渲染器上。因为它们以如此不同的方式绘制控件,很难在ToggleSwitch控件中制作出在所有不同场景中都有意义的通用颜色属性。
通过将颜色属性作为渲染器的一部分,可以比以往更自定义特定样式的外观。缺点是,为了做到这一点,必须创建一个新的渲染器实例,更改属性并将新渲染器分配给控件。但这并不难,演示程序将展示如何做到这一点。
在控件的1.1版本中,通过BeforeRendering事件传递渲染器实例,以便可以直接设置属性,而无需首先创建新实例。
最初想要的应用程序外观是带有拉丝金属旋钮的样式。以前见过的所有带有拉丝金属旋钮的控件都是以相同的方式制作的:通过在资源中嵌入在PhotoShop中创建的图像文件并在控件表面上绘制。
找到了一个PhotoShop教程,教如何创建这样的图像... 但这让感到困扰,阿斯伯格症让感到不安。嵌入文件并进行绘制并不像自己直接在控件上绘制那样“干净”。
即使有了PhotoShop教程,仍然不知道如何在C#中进行绘制。在Code Project上询问了一些人,但没有得到太多帮助。Pete告诉必须使用渐变画笔 - 这也知道,但还是不知道该怎么做。所以又Google了一些。找到了很多关于如何使用PathGradientBrush用径向渐变填充圆形的例子。但所有这些例子都展示了如何制作从圆的内中心到外边框(或相反)的渐变。而当然需要制作一个在圆的内部周围渐变的渐变。
这并不容易,但最后,找到了这个例子,它或多或少正是需要的:
// 示例代码
PathGradientBrush brush = new PathGradientBrush(ellipse);
brush.CenterColor = Color.LightGray;
brush.SurroundColors = new Color[] { Color.DarkGray };
brush.FocusScales = new PointF(0.75f, 0.75f);
brush.FocusPoints = new PointF[] { new PointF(0.5f, 0.5f) };
brush.Rectangle = new RectangleF(0, 0, 100, 100);
g.FillEllipse(brush, 0, 0, 100, 100);
所以开始将金属旋钮的图像分成渐变的饼状切片,然后一个接一个地绘制。这奏效了,但奇怪的是,发现如果使用旋钮的实际中心作为画笔的中心来绘制所有渐变,并没有得到预期的外观。为了获得正确的外观,必须稍微偏移每个画笔的中心。不知道为什么,但最后设法让它工作了,想。
“”绘制的拉丝金属旋钮可能看起来并不完全像PhotoShopped的那样好,但无论如何,对结果感到相当满意。更重要的是,不必在控件库中包含资源就可以让它工作。