<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>桌面端 on 云雾海的博客</title><link>https://blog.yunwuhai.com/categories/%E6%A1%8C%E9%9D%A2%E7%AB%AF/</link><description>Recent content in 桌面端 on 云雾海的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Wed, 14 Jan 2026 22:04:53 +0800</lastBuildDate><atom:link href="https://blog.yunwuhai.com/categories/%E6%A1%8C%E9%9D%A2%E7%AB%AF/index.xml" rel="self" type="application/rss+xml"/><item><title>关于WPF中xmlns的理解</title><link>https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/%E5%85%B3%E4%BA%8Ewpf%E4%B8%ADxmlns%E7%9A%84%E7%90%86%E8%A7%A3/</link><pubDate>Wed, 14 Jan 2026 22:04:53 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/%E5%85%B3%E4%BA%8Ewpf%E4%B8%ADxmlns%E7%9A%84%E7%90%86%E8%A7%A3/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/%E5%85%B3%E4%BA%8Ewpf%E4%B8%ADxmlns%E7%9A%84%E7%90%86%E8%A7%A3/cover.jpg" alt="Featured image of post 关于WPF中xmlns的理解" /&gt;&lt;h1 id="关于wpf中xmlns的理解"&gt;&lt;a href="#%e5%85%b3%e4%ba%8ewpf%e4%b8%adxmlns%e7%9a%84%e7%90%86%e8%a7%a3" class="header-anchor"&gt;&lt;/a&gt;关于WPF中xmlns的理解&#10;&lt;/h1&gt;&lt;h2 id="命名空间映射"&gt;&lt;a href="#%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%e6%98%a0%e5%b0%84" class="header-anchor"&gt;&lt;/a&gt;命名空间映射&#10;&lt;/h2&gt;&lt;p&gt;以一个通过Visual Studio直接创建的简单WPF项目为例，我们查看其&lt;code&gt;MainWindow.xaml&lt;/code&gt;文件，这是一个纯粹的窗口：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;&amp;lt;Window x:Class=&amp;#34;Test.MainWindow&amp;#34;&#10; xmlns=&amp;#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;#34;&#10; xmlns:x=&amp;#34;http://schemas.microsoft.com/winfx/2006/xaml&amp;#34;&#10; xmlns:d=&amp;#34;http://schemas.microsoft.com/expression/blend/2008&amp;#34;&#10; xmlns:mc=&amp;#34;http://schemas.openxmlformats.org/markup-compatibility/2006&amp;#34;&#10; xmlns:local=&amp;#34;clr-namespace:Test&amp;#34;&#10; mc:Ignorable=&amp;#34;d&amp;#34;&#10; Title=&amp;#34;MainWindow&amp;#34; Height=&amp;#34;450&amp;#34; Width=&amp;#34;800&amp;#34;&amp;gt;&#10; &amp;lt;Grid&amp;gt;&#10; &#10; &amp;lt;/Grid&amp;gt;&#10;&amp;lt;/Window&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;其中这一部分很难理解：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;x:Class=&amp;#34;Test.MainWindow&amp;#34;&#10;xmlns=&amp;#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;#34;&#10;xmlns:x=&amp;#34;http://schemas.microsoft.com/winfx/2006/xaml&amp;#34;&#10;xmlns:d=&amp;#34;http://schemas.microsoft.com/expression/blend/2008&amp;#34;&#10;xmlns:mc=&amp;#34;http://schemas.openxmlformats.org/markup-compatibility/2006&amp;#34;&#10;xmlns:local=&amp;#34;clr-namespace:Test&amp;#34;&#10;mc:Ignorable=&amp;#34;d&amp;#34;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;微软官方文档说，这个部分的内容其实叫XAML命名空间映射。&lt;/p&gt;&#10;&lt;h2 id="命名空间重命名"&gt;&lt;a href="#%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4%e9%87%8d%e5%91%bd%e5%90%8d" class="header-anchor"&gt;&lt;/a&gt;命名空间重命名&#10;&lt;/h2&gt;&lt;p&gt;我们知道，在C#中就存在命名空间，也就是我们的namespace。&lt;/p&gt;&#10;&lt;p&gt;而XAML则是微软基于XML开发的一种声明性语言，WPF是XAML最出名的使用者，而关于XAML的解析则由&lt;code&gt;.NET&lt;/code&gt;框架实现，它常被用于定义构造用户界面（UI）。&lt;/p&gt;&#10;&lt;p&gt;显然这是两种不同的语言，但显然两者需要进行交互，那么XAML就需要一种功能来调用命名空间，而这就是xmlns（XML/XAML namespace）的功能。&lt;/p&gt;&#10;&lt;p&gt;我们知道，对于C#中，调用其它命名空间的一种方式就是使用&lt;code&gt;using&lt;/code&gt;语句，比如：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c#" data-lang="c#"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;list&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;而&lt;code&gt;xmlns&lt;/code&gt;也是类似这样的功能，我们可以通过类似于以下的方式创建一个我们自定义于命名空间叫&lt;code&gt;Test&lt;/code&gt;下的一个&lt;code&gt;TestButton&lt;/code&gt;控件：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;xmlns:ts=&amp;#34;clr-namespace:Test&amp;#34;&#10;&amp;lt;ts:TestButton /&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;当然，如果更加准确一点形容，它在C#中应该更加类似于以下这种形式：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c#" data-lang="c#"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;ts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestButton&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;ts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestButton&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也就是说，&lt;code&gt;xmlns:（name）&lt;/code&gt;这种格式有点类似于引用命名空间并重命名或重映射，这里就是把&lt;code&gt;Test&lt;/code&gt;这个命名空间重映射为&lt;code&gt;ts&lt;/code&gt;了。&lt;/p&gt;&#10;&lt;p&gt;但是和C#中非常大的不同是，C#可以不重映射，比如直接通过以下形式实现：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c#" data-lang="c#"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestButton&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TestButton&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;但是XAML中要引用命名空间则必须先使用&lt;code&gt;xmlns&lt;/code&gt;语句将其重映射一遍，其中XAML中调用命名空间时使用的&lt;code&gt;clr-namespace:&lt;/code&gt;是一个固定关键词，在这个关键词后面可以通过类似C#的方式来写命名空间，比如如果&lt;code&gt;TestButton&lt;/code&gt;也是一个命名空间的话，那么就可以通过加&lt;code&gt;.&lt;/code&gt;的方式进行连接：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;xmlns:tb=&amp;#34;clr-namespace:Test.TestButton&amp;#34;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这一点用C#的思想去理解就可以了。&lt;/p&gt;&#10;&lt;p&gt;而事实上，我们的&lt;code&gt;xmlns:local&lt;/code&gt;就是这个功能，它提供的服务就是将项目的命名空间引用起来了，而这个&lt;code&gt;local&lt;/code&gt;可以改成任意其他名称，不过通常我们不用改。&lt;/p&gt;&#10;&lt;h2 id="默认命名空间"&gt;&lt;a href="#%e9%bb%98%e8%ae%a4%e5%91%bd%e5%90%8d%e7%a9%ba%e9%97%b4" class="header-anchor"&gt;&lt;/a&gt;默认命名空间&#10;&lt;/h2&gt;&lt;p&gt;现在我们大概理解了&lt;code&gt;xmlns&lt;/code&gt;的作用，那么让我们重新回顾语句，会发现其中有一个没加&lt;code&gt;:&lt;/code&gt;的语句，即：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;xmlns=&amp;#34;http://schemas.microsoft.com/winfx/2006/xaml/presentation&amp;#34;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这个语句其实代表了一个默认命名空间，而它后面跟的不是&lt;code&gt;clr-namespace:&lt;/code&gt;而是一个网址。&lt;/p&gt;&#10;&lt;p&gt;事实上这个网址并不是一个网页，而是统一资源标识符（URI），使用这种格式而非命名空间名字，最大的原因是为了保证全局唯一性，因为&lt;code&gt;microsoft.com&lt;/code&gt;这个网址是微软拥有的，所以这个URI只有微软能用，这个URI的信息主要如下：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-markdown" data-lang="markdown"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;http://schemas.microsoft.com/winfx/2006/xaml/presentation&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; | | | | |&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; 公司 规范 年份 技术 具体组件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;其中&lt;code&gt;schemas&lt;/code&gt;代表模式或规范，而&lt;code&gt;WinFx/2006&lt;/code&gt;就是WPF的代号和规范的年份，&lt;code&gt;xaml&lt;/code&gt;代表用于XAML技术，&lt;code&gt;presentation&lt;/code&gt;代表WPF的Presentation层。&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;补充一个使用技巧：当你想知道某个命名空间URI对应的实际程序集时，可以查看项目的&lt;code&gt;*.csproj&lt;/code&gt;文件，里面会有相应的引用。比如默认WPF命名空间对应多个程序集引用。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;简单理解，这一个自动生成的&lt;code&gt;xmlns&lt;/code&gt;代表的就是&lt;code&gt;WPF&lt;/code&gt;的整个库，而它没有&lt;code&gt;:&lt;/code&gt;则是因为它将作为默认空间使用，在XAML中任何没有加前缀的控件，都会优先在这个命名空间里面寻找，比如：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;&amp;lt;Button Content=&amp;#34;Button&amp;#34; HorizontalAlignment=&amp;#34;Center&amp;#34; VerticalAlignment=&amp;#34;Center&amp;#34;/&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;和我们前面的&lt;code&gt;TestButton&lt;/code&gt;的调用方法不同，前面并没有加任何&lt;code&gt;name:&lt;/code&gt;，所以这种&lt;code&gt;Button&lt;/code&gt;就会直接在&lt;code&gt;xmlns&lt;/code&gt;指向的默认命名空间中寻找。&lt;/p&gt;&#10;&lt;p&gt;否则，我们在前面加一个&lt;code&gt;ts:&lt;/code&gt;：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;&amp;lt;ts:Button Content=&amp;#34;Button&amp;#34; HorizontalAlignment=&amp;#34;Center&amp;#34; VerticalAlignment=&amp;#34;Center&amp;#34;/&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;只是加了一个&lt;code&gt;ts:&lt;/code&gt;，现在就必须在一个&lt;code&gt;xmlns:ts&lt;/code&gt;的命名空间里面寻找了，如果前面没有引用这个空间，或者空间里面没有&lt;code&gt;Button&lt;/code&gt;这个类，那么就会报错。&lt;/p&gt;&#10;&lt;h2 id="特殊的x"&gt;&lt;a href="#%e7%89%b9%e6%ae%8a%e7%9a%84x" class="header-anchor"&gt;&lt;/a&gt;特殊的x&#10;&lt;/h2&gt;&lt;p&gt;我们发现在我们开始举例的XAML代码里面，最开始有一个&lt;code&gt;x:Class&lt;/code&gt;，而后面才出现了&lt;code&gt;xmlns:x=http://schemas.microsoft.com/winfx/2006/xaml&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;并且通过我们刚才对URI的理解，我们发现这个&lt;code&gt;x&lt;/code&gt;的URI和刚刚的&lt;code&gt;xmlns&lt;/code&gt;的很相似，只是它的URI少了&lt;code&gt;/presentation&lt;/code&gt;，这代表它似乎是直接对XAML本身的规范。&lt;/p&gt;&#10;&lt;p&gt;事实上在XAML中&lt;code&gt;x&lt;/code&gt;也确实是一个比较特殊的命名空间，它提供的不是某些控件，而是XAML本身的一些语言特性或特殊操作。&lt;/p&gt;&#10;&lt;p&gt;而&lt;code&gt;x:Class&lt;/code&gt;就是这个命名空间中一个比较重要的操作，它提供了XAML和C#后台代码的连接，比如在XAML中我们看到：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;x:Class=&amp;#34;Test.MainWindow&amp;#34;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这其实对应了C#后台代码的：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-c#" data-lang="c#"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Test&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;partial&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MainWindow&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Window&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;MainWindow&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;InitializeComponent&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;可以发现，它们的命名空间和类名完美对应上了，在编译时，两个板块才能够连接在一起。&lt;/p&gt;&#10;&lt;p&gt;而它的原理就是指定了这个XAML编译后生成的局部类(partial class)应该与哪个C#类合并，这也解释了为什么C#中的类是&lt;code&gt;partial&lt;/code&gt;的。&lt;/p&gt;&#10;&lt;p&gt;显然&lt;code&gt;x&lt;/code&gt;在工作中并不是调用某个C#的类或方法，而是作为一种特殊工具来操作XAML本身。&lt;/p&gt;&#10;&lt;p&gt;而&lt;code&gt;x&lt;/code&gt;的常用功能很多，比如我们在XAML中通过语句添加了一个Button控件，就像我们刚才那样：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;&amp;lt;Button Content=&amp;#34;Button&amp;#34; HorizontalAlignment=&amp;#34;Center&amp;#34; VerticalAlignment=&amp;#34;Center&amp;#34;/&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;我们或许可以在VS的布局界面看到这个按钮，但是我们该如何在C#中调用这个按钮呢，其实要做的就是添加&lt;code&gt;x:Name&lt;/code&gt;，比如：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;&amp;lt;Button x:Name=&amp;#34;button&amp;#34; Content=&amp;#34;Button&amp;#34; HorizontalAlignment=&amp;#34;Center&amp;#34; VerticalAlignment=&amp;#34;Center&amp;#34;/&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;现在，我们就可以在C#后台代码中通过变量名&lt;code&gt;button&lt;/code&gt;直接访问控制这个控件了，操作变得非常简单。&lt;/p&gt;&#10;&lt;p&gt;关于&lt;code&gt;x&lt;/code&gt;，常用的指令有：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;x:Class&lt;/code&gt; - 连接XAML和C#后台代码&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;x:Name&lt;/code&gt; - 给控件起名字，用于后台访问&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;x:Key&lt;/code&gt; - 给资源（样式、模板等）起标识符&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;x:Type&lt;/code&gt; - 表示一个类型&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;x:Static&lt;/code&gt; - 引用静态成员&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;另外&lt;code&gt;x&lt;/code&gt;这个名字是可以改的，因为它只是一个约定俗成的名字，其本身仍然遵守XAML的语法规则。但是通常不建议修改，因为一些库里面习惯了这个约定俗成的名字，改了很可能会出现一些意想不到的错误，而且也会降低代码可读性。&lt;/p&gt;&#10;&lt;h2 id="用于设计的d"&gt;&lt;a href="#%e7%94%a8%e4%ba%8e%e8%ae%be%e8%ae%a1%e7%9a%84d" class="header-anchor"&gt;&lt;/a&gt;用于设计的d&#10;&lt;/h2&gt;&lt;p&gt;我们还可以看到一个自动生成的命名空间：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;xmlns:d=&amp;#34;http://schemas.microsoft.com/expression/blend/2008&amp;#34;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;d=Design，代表设计时。&lt;/p&gt;&#10;&lt;p&gt;它和&lt;code&gt;x&lt;/code&gt;类似，不直接提供控件但是提供一些特殊服务，而这里的服务则是一些供Visual Studio设计器或者Blend中显示，而运行时会消失的特殊属性，比如：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;&amp;lt;Window&#10; xmlns:d=&amp;#34;http://schemas.microsoft.com/expression/blend/2008&amp;#34;&#10; d:DesignHeight=&amp;#34;450&amp;#34;&#10; d:DesignWidth=&amp;#34;800&amp;#34;&amp;gt;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这是在设计器里面提供了一个预览尺寸，方便在设计界面的时候看到效果，但是实际运行时窗口的大小则和这两个属性无关。&lt;/p&gt;&#10;&lt;p&gt;在实际项目开发中，特别是使用MVVM模式时，&lt;code&gt;d:&lt;/code&gt;命名空间提供的设计时数据功能非常有用。比如：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;d:DataContext=&amp;#34;{d:DesignInstance Type=local:MainViewModel}&amp;#34;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这可以在设计器里显示绑定数据的效果，避免&amp;quot;设计时一片空白&amp;quot;的问题。所以对于专业WPF开发，&lt;code&gt;d:&lt;/code&gt;是很有价值的工具。&lt;/p&gt;&#10;&lt;p&gt;不过你如果担心它会污染你的代码，出现一些意想不到的错误，其实可以放心，因为下面一个命名空间的功能解决了这个问题。&lt;/p&gt;&#10;&lt;h2 id="标记兼容性的mc"&gt;&lt;a href="#%e6%a0%87%e8%ae%b0%e5%85%bc%e5%ae%b9%e6%80%a7%e7%9a%84mc" class="header-anchor"&gt;&lt;/a&gt;标记兼容性的mc&#10;&lt;/h2&gt;&lt;p&gt;继续往下看，我们可以发现两个语句：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code class="language-xaml" data-lang="xaml"&gt;xmlns:mc=&amp;#34;http://schemas.openxmlformats.org/markup-compatibility/2006&amp;#34;&#10;mc:Ignorable=&amp;#34;d&amp;#34;&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;这里面都出现了&lt;code&gt;mc&lt;/code&gt;命名空间，mc=Markup Compatibility，即标记兼容性。&lt;/p&gt;&#10;&lt;p&gt;这个命名空间通常与&lt;code&gt;d:&lt;/code&gt;配合使用，它会告诉编译器，有些标记只是设计时使用的，运行的时候可以忽略，即&lt;code&gt;mc:Ignorable=&amp;quot;d&amp;quot;&lt;/code&gt;。&lt;/p&gt;&#10;&lt;p&gt;如果没有这个声明，编译器在看到&lt;code&gt;d:DesignHeight&lt;/code&gt;时可能会产生困惑，这个属性是什么，自己似乎并未见过（因为这个功能只在设计器或Blend中被调用实现了）。&lt;/p&gt;&#10;&lt;p&gt;此外，利用mc的一些特性，可以将某些实验功能或未来版本的功能标记为可忽略，这样旧版本的编译器就不会报错。&lt;/p&gt;&#10;&lt;p&gt;同样，大部分时候我们不需要关注这个标记的用法，需要用的时候再自行查询即可。&lt;/p&gt;&#10;&lt;h2 id="总结xmlns的层次结构"&gt;&lt;a href="#%e6%80%bb%e7%bb%93xmlns%e7%9a%84%e5%b1%82%e6%ac%a1%e7%bb%93%e6%9e%84" class="header-anchor"&gt;&lt;/a&gt;总结：xmlns的层次结构&#10;&lt;/h2&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;默认命名空间&lt;/strong&gt; (&lt;code&gt;xmlns=&amp;quot;...&amp;quot;&lt;/code&gt;) - WPF核心控件库&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;x命名空间&lt;/strong&gt; (&lt;code&gt;xmlns:x=&amp;quot;...&amp;quot;&lt;/code&gt;) - XAML语言特性&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;自定义映射&lt;/strong&gt; (&lt;code&gt;xmlns:别名=&amp;quot;clr-namespace:...&amp;quot;&lt;/code&gt;) - 引用自己的代码&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;设计时支持&lt;/strong&gt; (&lt;code&gt;xmlns:d=&amp;quot;...&amp;quot;&lt;/code&gt;) - 设计器辅助功能&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;兼容性处理&lt;/strong&gt; (&lt;code&gt;xmlns:mc=&amp;quot;...&amp;quot;&lt;/code&gt;) - 版本和工具兼容&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;这种分层设计让XAML既能使用框架控件，又能扩展自定义功能，同时支持设计时和运行时的不同需求。&lt;/p&gt;&#10;</description></item><item><title>Winform自定义一个圆形按钮</title><link>https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/</link><pubDate>Sun, 21 Mar 2021 22:45:35 +0800</pubDate><guid>https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/</guid><description>&lt;img src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/cover.jpg" alt="Featured image of post Winform自定义一个圆形按钮" /&gt;&lt;p&gt;&lt;em&gt;因为我是电子专业的，学校没教过C#，学下来也基本上都是野路子东看西看基于需求地乱学，故而对C#的理解并不是很深。然而个人项目需要自定义一个控件来实现动态连线功能，不得不从入门直接跳到高级应用进行学习，这里做一个记录以对后面有类似需要的朋友一个参考。目前只是实现了一个简单的变色按钮功能，但是需要使用的大部分技术都用上了，如果需要实现其它更复杂功能的话就把本文当个抛砖引玉吧。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;&lt;em&gt;本文参考了《[C#] （原创）一步一步教你自定义控件——01，TrackBar》,但是在其基础上增加了设置控件区域的功能。另外因为那篇文章被很多人盗用，原文已经不可考，所以不贴地址给他们引流了，如果有需要可以直接百度这个名字即可。&lt;/em&gt;&lt;/p&gt;&#10;&lt;h2 id="新建工程"&gt;&lt;a href="#%e6%96%b0%e5%bb%ba%e5%b7%a5%e7%a8%8b" class="header-anchor"&gt;&lt;/a&gt;新建工程&#10;&lt;/h2&gt;&lt;p&gt;新建一个项目，选择Windows窗体控件库(.NET Framwork)，然后选择地址、命名。&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="361px" data-flex-grow="150" height="680" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/739585ea15f492b0d84f5b50c03bf306.webp" width="1024"&gt;&lt;p&gt;正常情况下工程里应该有一个UserControl1.cs文件，不要它，直接删除，然后新建一个没有模板的类。&lt;/p&gt;&#10;&lt;p&gt;将此类的访问属性改为public并且继承自Control，如果Control下出现波浪线报错的话是因为没有引用其命名空间，可以按住&lt;code&gt;Alt + Enter&lt;/code&gt;后选中第一个命名空间再按一次Enter进行修改，VS将自动添加上&lt;code&gt;using System.Windows.Forms;&lt;/code&gt;。&lt;/p&gt;&#10;&lt;h2 id="添加属性"&gt;&lt;a href="#%e6%b7%bb%e5%8a%a0%e5%b1%9e%e6%80%a7" class="header-anchor"&gt;&lt;/a&gt;添加属性&#10;&lt;/h2&gt;&lt;p&gt;然后我们根据需求进行添加属性，因为这个功能只是需要实现一个圆形开关，那么我们需要知道的属性就有开关打开时的颜色，开关关闭时的颜色，圆形开关的直径，开关的状态四个属性。颜色使用Color类进行定义，直径使用int或者float进行定义，开关状态用布尔进行定义，并且给他们赋值上初始值。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;openColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromArgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 开启默认浅绿色&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;closeColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromArgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 关闭默认浅红色&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 直径默认20，且为整数类型&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#9;&lt;span class="c1"&gt;// 默认关闭&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后为他们添加上各自的访问器：&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="352px" data-flex-grow="146" height="152" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/fd57a6439e9358d15ad2c206b752bba2.webp" width="223"&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="361px" data-flex-grow="150" height="146" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/543f0ac40433a38bd90034f48897f3fe.webp" width="220"&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="508px" data-flex-grow="211" height="161" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/d0751f17324da7995052ef8543f8f0b0.webp" width="341"&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="630px" data-flex-grow="262" height="166" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/6e40163512af66c91631e13ad14c48a1.webp" width="436"&gt;&lt;p&gt;我们可以注意到，他们各自的get访问器其实没啥特别的，但是set访问器中除了基本的赋值以外，每个访问器中都有&lt;code&gt;Invalidate();&lt;/code&gt;这么一句，它的工作目的是重新绘制一遍控件。&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="1054px" data-flex-grow="439" height="71" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/4a719da808aecb7b0ce4feedbf6ef341.webp" width="312"&gt;&lt;p&gt;一般来说，如果你调整的这个属性将会影响到当前控件的外观，那么就有必要加上这么一句，它的功能类似于将原本的控件从你的屏幕上删除，然后根据新的定义创建一个新的控件。&lt;/p&gt;&#10;&lt;p&gt;然后我们再观察直径的访问器中使用了&lt;code&gt;Size = new Size(diameter, diameter);&lt;/code&gt;这么一句话，它的目的是什么呢？其实从语义上就可以推测知道，是重新赋值了大小属性，其中宽度和长度变成了直径的。但是理论上其实不加这句也没有问题，因为我们后面会使用一个指定边界函数实现相同功能，但是如果不加上的话我们在使用Winform的设计模式的时候就容易出现bug，调整大小的时候，如果调大就会出现内容消失的情况，需要手动去调整一下才能重新刷新出来。我理解的原因是设计模式其实开启了一个模拟窗口，但是这里我们修改属性值的时候只有一些基础属性会被显示出来而不会触发具体的方法函数。故而我们不能运行后面那个指定边界函数进行样式的刷新，导致出现视觉bug。&lt;/p&gt;&#10;&lt;p&gt;然后另一个需要注意的是，我们在IsOpen中使用了一个TestSwitch的事件，如果我们的开关状态发生了改变，那么就会触发这个事件。后来如果我们需要，可以为这个事件增加功能，一旦IsOpen被赋值，就可以执行相应的功能。&lt;/p&gt;&#10;&lt;p&gt;不过我们如果需要使用这个功能的话，就还需要添加上委托和事件的定义，一般情况下我们在命名空间内写委托，然后在类里定义事件。&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="3144px" data-flex-grow="1310" height="60" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/54bdcf19c95fe0409915e213ac2d364a.webp" width="786"&gt;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="3170px" data-flex-grow="1320" height="43" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/e38aaa0fc11b41260f72bc0d54176302.webp" width="568"&gt;&lt;p&gt;但是，我们知道如果想使用VS的设计器的话可以利用属性栏修改控件的属性，所以我们自定义的控件自然也想要相同的功能。此时需要输入&lt;code&gt;[Category(&amp;quot;属性分类&amp;quot;), Description(&amp;quot;功能描述&amp;quot;)]&lt;/code&gt;即可添加这些功能。其中属性分类的目的是为了方便我们找到我们自定义的这些功能，而功能描述则是方便使用的时知道该如何填入所需的属性。如果这里出现了报错，同样是因为没有引用所需的命名空间，只需要像前面一样按住&lt;code&gt;Alt + Enter&lt;/code&gt;然后进行修正即可。&lt;/p&gt;&#10;&lt;p&gt;以下是我定义的所有的属性以及他们的描述。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&#9;&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;openColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromArgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Category(&amp;#34;DemoUI&amp;#34;), Description(&amp;#34;开启时的颜色&amp;#34;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;OpenColor&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;openColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;openColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Invalidate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;closeColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FromArgb&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;255&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;128&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Category(&amp;#34;DemoUI&amp;#34;), Description(&amp;#34;关闭时的颜色&amp;#34;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;Color&lt;/span&gt; &lt;span class="n"&gt;CloseColor&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;closeColor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;closeColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Invalidate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Category(&amp;#34;DemoUI&amp;#34;), Description(&amp;#34;圆直径&amp;#34;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;diameter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Size&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;diameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;diameter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Invalidate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="na"&gt; [Category(&amp;#34;DemoUI&amp;#34;), Description(&amp;#34;开关状态&amp;#34;)]&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt; &lt;span class="n"&gt;IsOpen&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;get&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="k"&gt;set&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Invalidate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;TestSwitch&lt;/span&gt;&lt;span class="p"&gt;?.&lt;/span&gt;&lt;span class="n"&gt;Invoke&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TestEventArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isOpen&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="添加方法"&gt;&lt;a href="#%e6%b7%bb%e5%8a%a0%e6%96%b9%e6%b3%95" class="header-anchor"&gt;&lt;/a&gt;添加方法&#10;&lt;/h2&gt;&lt;p&gt;完成了上述工作后，我们还需要为这个控件添加一些方法，然后他就可以成为真正的控件了。&lt;/p&gt;&#10;&lt;p&gt;首先，我们需要重写SetBoundsCore方法，这个方法可以定义控件的边界工作，根据微软给的定义，通过这个方法可以控制控件的Left、Top、Width、Height和BoundSpecified值，其中Left和Top控制着控件的位置，而Width和Height控制着控件边界的大小，而最后一个参数是枚举，不过功能没搞懂是做啥的，但是实际应用中不管也没事，因为我们一般都是重写Width和Height就好了。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="kd"&gt;protected&lt;/span&gt; &lt;span class="kd"&gt;override&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="n"&gt;SetBoundsCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;height&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;BoundsSpecified&lt;/span&gt; &lt;span class="n"&gt;specified&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="k"&gt;base&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetBoundsCore&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;specified&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;通过这个重写，我们可以让边界大小始终等于圆的直径，其中base的意思是在重写是基于原本的方法进行重写。&lt;/p&gt;&#10;&lt;p&gt;然后我们还需要设置一个可以改变开关值的方法，因为我希望得到的效果是在点击控件时不会改变，而在放开时：如果在控件内放开鼠标可以改变值，而如果在控件外放开鼠标则保持原本只不变。这种情况下我们只需要重写OnMouseUp控件就好了，我重写的内容如下，内容一看就懂，就不多写注释了：&lt;/p&gt;&#10;&lt;pre tabindex="0"&gt;&lt;code&gt;protected override void OnMouseUp(MouseEventArgs e)&#10;{&#10;&#9;base.OnMouseUp(e);&#10; &#9;if (Region.IsVisible(e.Location))&#10; &#9;{&#10; &#9;&#9;if (IsOpen)&#10;&#9;&#9;{&#10;&#9;&#9;&#9;IsOpen = false;&#10; &#9;&#9;}&#10; &#9;&#9;else&#10; &#9;&#9;{&#10; &#9;&#9;&#9;IsOpen = true;&#10; &#9;&#9;}&#10; &#9;}&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;然后我们再重写OnPaint方法，这个方法在我们每次调用Invalidate()的时候都会用到（就是前面每次我们调用set访问器的时候都会使用的那个函数），它的功能就是把控件在屏幕上画一遍（只是画一遍，并没有Invalidate中的清除原控件的功能）。&lt;/p&gt;&#10;&lt;p&gt;这里我们使用GDI+来画控件，当然事实上你也可以调用图片然后来实现，他们的原理相似。&lt;/p&gt;&#10;&lt;p&gt;首先我们需要让GDI+的分辨率提高（其实这个控件太简单了可能用不着，但是如果未来在画一些复杂的控件的时候可能需要）：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SmoothingMode&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing2D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SmoothingMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;HighQuality&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;然后我们现在需要把圆画出来，因为在后面要切割，所以这里其实怎么画都没问题，不过为了严谨我们还是正规点画个圆就行。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isOpen&lt;/span&gt; &lt;span class="p"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FillEllipse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SolidBrush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OpenColor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;else&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#9;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FillEllipse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;SolidBrush&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CloseColor&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这两句话的意思是使用开启颜色或关闭颜色画个直径为我们设定直径的圆。&lt;/p&gt;&#10;&lt;p&gt;然后最重要的一步来了，虽然我们当前画出来了一个圆，它的样子和我们所需要的样式相同了，但是其本质上还是一个矩形，只是矩形上面画了一个圆而已，而在点击的时候其实点在这个矩形的空白部分我们仍然等同于点到了这个控件。&lt;/p&gt;&#10;&lt;p&gt;这时候，我们需要用Region把这个圆的区域抠出来，具体做法就是新建一个&lt;code&gt;System.Drawing.Drawing2D.GraphicsPath&lt;/code&gt;的对象，然后用它在正确位置抠出一个和我们画出的圆一样大小的圆，这样就刚好吧我们需要的圆抠出来了。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing2D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraphicsPath&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing2D&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GraphicsPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AddEllipse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Diameter&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;Region&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Region&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;现在，我们就真正有了一个圆形的开关了。&lt;/p&gt;&#10;&lt;h2 id="添加事件"&gt;&lt;a href="#%e6%b7%bb%e5%8a%a0%e4%ba%8b%e4%bb%b6" class="header-anchor"&gt;&lt;/a&gt;添加事件&#10;&lt;/h2&gt;&lt;p&gt;之前我们在属性中使用的事件，可以自己新增事件库进行管理，新建类，然后将其设为public并继承自EventArgs，接着新建事件并设计这个事件的参数和执行的操作。&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-csharp" data-lang="csharp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;DemoControls&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestEventArgs&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;EventArgs&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="n"&gt;TestEventArgs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;Value&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;同时我们还可以把这个事件设为默认事件，在开头部分我们定义这个控件类的默认事件为我们前面注册的TestSwitch。&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="1488px" data-flex-grow="620" height="60" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/20b434b3f3024c7e349b2480e5496d4f.webp" width="372"&gt;&lt;h2 id="使用这个控件"&gt;&lt;a href="#%e4%bd%bf%e7%94%a8%e8%bf%99%e4%b8%aa%e6%8e%a7%e4%bb%b6" class="header-anchor"&gt;&lt;/a&gt;使用这个控件&#10;&lt;/h2&gt;&lt;p&gt;那么该如何使用这个控件呢？你可以新建一个工程（一般情况下建议新建工程来使用控件，而控件库单独用一个工程来管理，你未来所有的控件都可以放在控件库里），如果在本解决方案中的话，只需要在解决方案管理器中右键点击你的控件库工程名，选择生成，然后你就可以当前解决方案的任意工程中使用你控件库里的所有控件了。&lt;/p&gt;&#10;&lt;p&gt;而如果你需要在外部使用你的控件库，可以在生成后，进入到你的工程文件夹，Debug或者Release文件夹里的dll文件。如果你需要在某一个工程中使用这个控件的话，就在新工程里点击工具-选择工具箱项，点击浏览，然后添加刚才那个dll文件即可。&lt;/p&gt;&#10;&lt;p&gt;现在我们在当前解决方案试试看吧：&lt;/p&gt;&#10;&lt;p&gt;生成文件、新建工程、然后开始使用设计页面，可以发现设计页面最开头添加了我们的控件库：&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="607px" data-flex-grow="253" height="107" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/533f3dc5f5f6af437880e1b5a233b25e.webp" width="271"&gt;&lt;p&gt;然后我们拖出来两个，设置一下他们的大小和颜色：&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="398px" data-flex-grow="166" height="127" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/ee732094f8a4b7749553b2667701621e.webp" width="211"&gt;&lt;p&gt;同时双击第一个控件增添事件功能：&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="2034px" data-flex-grow="847" height="80" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/6cced7a1cc2475ecca74f99e70f751fa.webp" width="678"&gt;&lt;p&gt;最后启动：&lt;/p&gt;&#10;&lt;img alt="在这里插入图片描述" class="gallery-image" data-flex-basis="399px" data-flex-grow="166" height="482" loading="lazy" sizes="(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px" src="https://blog.yunwuhai.com/posts/%E6%A1%8C%E9%9D%A2%E7%AB%AF/winform%E8%87%AA%E5%AE%9A%E4%B9%89%E4%B8%80%E4%B8%AA%E5%9C%86%E5%BD%A2%E6%8C%89%E9%92%AE/img/f03246cf7249a979453708845785e066.webp" width="802"&gt;&lt;p&gt;成功。&lt;/p&gt;&#10;&lt;p&gt;&lt;a class="link" href="https://github.com/yunwuhai/TestControlsLib" target="_blank" rel="noopener"&#10; &gt;完整的工程下载地址&lt;/a&gt;&lt;/p&gt;&#10;</description></item></channel></rss>