100165633.htm

来自「C#高级编程(第三版),顶死你们。。 。up」· HTM 代码 · 共 321 行 · 第 1/4 页

HTM
321
字号
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">这个示例代码还说明了简化的</span><span lang="EN-US">Command</span><span style="FONT-FAMILY: 宋体">类的用法</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">一种常见的设计模式</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">。这个示例中使用的</span><span lang="EN-US">MenuCommand</span><span style="FONT-FAMILY: 宋体">是在用户选择关联菜单中的一项时触发的,它会继续调用方法的接收器,在本例中是对象及所属的方法。这也有助于使接收器对象中的代码更容易与用户界面代码隔离开来。下面几节将解释这些代码。</span></p>
<h4 style="FTEL: 21.45pt"><span lang="EN-US">1. </span><span style="FONT-FAMILY: 黑体">生成的表和行</span></h4>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">本章前面的</span><span lang="EN-US">XSD</span><span style="FONT-FAMILY: 宋体">示例显示的代码是在使用</span><span lang="EN-US">Visual Studio .NET</span><span style="FONT-FAMILY: 宋体">编辑器生成一组数据访问类时生成的,下面的类显示了</span><span lang="EN-US">DataTable</span><span style="FONT-FAMILY: 宋体">需要的方法,这是为这个类生成的最小一组代码</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">它们都是手工生成的</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public class CustomerTable : DataTable </span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public CustomerTable() : base(&quot;Customers&quot;)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Columns.Add(&quot;CustomerID&quot;, typeof(string));</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Columns.Add(&quot;CompanyName&quot;, typeof(string));</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; this.Columns.Add(&quot;ContactName&quot;, typeof(string));</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; protected override System.Type GetRowType()</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return typeof(CustomerRow);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; protected override DataRow NewRowFromBuilder(DataRowBuilder builder)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(DataRow) new CustomerRow(builder);</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">首先,</span><span lang="EN-US">DataTable</span><span style="FONT-FAMILY: 宋体">必须重写</span><span lang="EN-US">GetRowType()</span><span style="FONT-FAMILY: 宋体">方法,这是在生成表的新行时由</span><span lang="EN-US">.NET</span><span style="FONT-FAMILY: 宋体">在内部使用的。这个方法应返回用于表示每一行的类型。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">其次,需要执行</span><span lang="EN-US">NewRowFromBuilder()</span><span style="FONT-FAMILY: 宋体">,它也是在为表创建新行时由运行库调用的。这对于最小执行方式是足够的。但本例要给</span><span lang="EN-US">DataTable</span><span style="FONT-FAMILY: 宋体">添加列,而且事先知道列的内容,因此可以添加它们。对应的</span><span lang="EN-US">CustomerRow</span><span style="FONT-FAMILY: 宋体">类是相当简单的,它为行中的每一列执行属性,然后执行最终显示在关联菜单中的方法:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public class CustomerRow : ContextDataRow</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public CustomerRow(DataRowBuilder builder) : base(builder)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public string CustomerID</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; get { return (string)this[&quot;CustomerID&quot;];}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set { this[&quot;CustomerID&quot;] = value;}</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; // Other properties omitted for clarity</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; [ContextMenu(&quot;Blacklist Customer&quot;)]</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public void Blacklist()</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Do something</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; [ContextMenu(&quot;Get Contact&quot;,Default=true)]</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public void GetContact()</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Do something else</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">该类派生于</span><span lang="EN-US">ContextDataRow</span><span style="FONT-FAMILY: 宋体">,包括相应的</span><span lang="EN-US">getter/setter</span><span style="FONT-FAMILY: 宋体">方法,其属性名与每个字段是相同的,然后添加一些方法,在反射到类上时会使用这些方法:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; [ContextMenu(&quot;Blacklist Customer&quot;)]</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public void Blacklist()</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // Do something</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">每个要显示在关联菜单中的方法都有相同的签名,且包括定制的</span><span lang="EN-US">ContextMenu</span><span style="FONT-FAMILY: 宋体">属性。</span></p>
<h4 style="FTEL: 21.45pt"><span lang="EN-US">2. </span><span style="FONT-FAMILY: 黑体">使用属性</span></h4>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">编写</span><span lang="EN-US">ContextMenu</span><span style="FONT-FAMILY: 宋体">属性的理念是要能为给定的菜单选项提供一个自由文本名称,下面的示例还使用了一个</span><span lang="EN-US">Default</span><span style="FONT-FAMILY: 宋体">标志,它用于指定默认的菜单选项。下面给出完整的属性类:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">[AttributeUsage(AttributeTargets.Method,AllowMultiple=false,Inherited=true)]</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">public class ContextMenuAttribute : System.Attribute</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public ContextMenuAttribute(string caption)</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; {</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Caption = caption;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Default = false;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; }</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public readonly string Caption;</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public bool Default;</span></p>
<p class="2" style="MARGIN-TOP: 0cm; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">}</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">类的</span><span lang="EN-US">AttributeUsage</span><span style="FONT-FAMILY: 宋体">属性把</span><span lang="EN-US">ContextMenuAttribute</span><span style="FONT-FAMILY: 宋体">标记为惟一可以在方法上使用的属性,它还定义了在任何给定的方法上只有该对象的一个实例。</span><span lang="EN-US">Inherited=true</span><span style="FONT-FAMILY: 宋体">子句定义了属性是否可以放在一个超类方法上,且仍由子类反映出来。</span></p>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">可以考虑把许多其他成员添加到这个属性上,例如:</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体">菜单选项的热键</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体">要显示的图像</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体">要显示在工具栏中的文本,当鼠标放在菜单选项上时,就会显示该文本</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体">帮助环境</span><span lang="EN-US">ID</span></p>
<h4 style="FTEL: 21.45pt"><span lang="EN-US">3. </span><span style="FONT-FAMILY: 黑体">分派方法</span></h4>
<p class="MsoNormal"><span style="FONT-FAMILY: 宋体">当菜单显示在</span><span lang="EN-US">.NET</span><span style="FONT-FAMILY: 宋体">中时,每个菜单选项都通过委托的方式链接到该选项的处理代码上。把菜单选项链接到代码上的机制中,有两个基本的选项。</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体">执行与</span><span lang="EN-US">System.EventHandler</span><span style="FONT-FAMILY: 宋体">有相同签名的方法,其定义如下:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public delegate void EventHandler(object sender, EventArgs e);</span></p>
<p class="1" style="MARGIN-LEFT: 37.55pt; FTEL: -16.1pt"><span lang="EN-US">●<span style="FONT: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="FONT-FAMILY: 宋体">定义一个代理类,它执行上述委托,调用接收的类。这就称为</span><span lang="EN-US">Command</span><span style="FONT-FAMILY: 宋体">模型,也是本例选择的模型。</span></p>
<p class="MsoNormal"><span lang="EN-US">Command</span><span style="FONT-FAMILY: 宋体">模型通过一个简单的中间类把发送者和接收者分离开来。对于本例,该模型就矫枉过正了,但可以使每个</span><span lang="EN-US">DataRow</span><span style="FONT-FAMILY: 宋体">上的方法更简单一些</span><span lang="EN-US">(</span><span style="FONT-FAMILY: 宋体">因为它们不需要给委托传送参数</span><span lang="EN-US">)</span><span style="FONT-FAMILY: 宋体">,而且扩展性更高:</span></p>
<p class="2" style="MARGIN-TOP: 8.15pt; MARGIN-LEFT: 21.45pt; MARGIN-RIGHT: 0cm; FTEL: 18.45pt"><span lang="EN-US">public class MenuCommand</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">{</span></p>
<p class="2" style="MARGIN-LEFT: 21.45pt; FTEL: 18.45pt"><span lang="EN-US">&nbsp;&nbsp; public MenuCommand(object receiver, MethodInfo method)</span></p>

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?