知识大全 ASP.NET可交互式位图窗体设计(下)

Posted

篇首语:对于攀登者来说,失掉往昔的足迹并不可惜,迷失了继续前时的危险。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 ASP.NET可交互式位图窗体设计(下)相关的知识,希望对你有一定的参考价值。

ASP.NET可交互式位图窗体设计(下)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!

  维护两个列表

  因为我们要改变对象的填充颜色以实现 Change fill to hot pink 按钮 因此维护了两个可绘制对象列表 一个列表是全部对象 另一个列表是可填充对象 我们为这两个列表都使用了 ArrayList 类 ArrayList 对象包含一组 Object 引用 这样一个 ArrayList 可以包含系统中任何类型的混合

  这实际上并没有什么帮助 我们希望 ArrayList 仅仅包括可绘制/可填充对象 为此 我们将 ArrayList 对象设为私有 然后将向列表添加对象的过程设为一个方法 该方法只接受一个 DShape

  当使用 Add 方法向列表中添加对象时 我们将所有对象添加到 wholeList 中 然后检查对象是否还应添加到 filledList 集合中

  请记住 Add 方法(以及列表)具有类型安全特性 它只接受 DShape(或者从 DShape 派生的类型 例如我们在上面创建的所有类型) 您不能将整数或字符串添加到列表中 这样我们便可以知道这个列表只包含可绘制对象 能够确知这一点是很方便的!

  绘制项

  我们还有一个 DrawList 方法 用于在它作为参数传递的 Graphics 对象上绘制列表中的对象 此方法具有两种情况 如果列表为空 它绘制一个字符串 说明列表为空 如果列表不为空 它使用一个 for each 构造函数遍历该列表 并在每个对象上调用 Draw 实际的遍历和绘图代码再简单不过了

    foreach (DShape d in wholeList)d Draw(g);    由于列表是封装的 我们知道它具有类型安全特性 因此可以仅调用 Draw 方法而不必检查对象的类型

  最后 我们的 Change fills to hot pink(将填充色更改为粉红)按钮需要一个对所有可填充对象的引用数组 以便更改其 FillBrushColor 属性 虽然可以编写一个方法遍历列表并将颜色更改为传入的值 但这一次 Dr GUI 选择了返回一个对象引用数组 幸运的是 ArrayList 类具有一个 ToArray 方法 利用它可以创建一个传递数组 该方法获取我们需要的数组元素类型 从而可以传递回所需的类型 IFillable 数组

    public IFillable[] GetFilledList() return (IFillable[])filledList ToArray(typeof(IFillable));    在两种语言中 我们都使用了一个内置运算符获取给定类型的 Type 对象 在 C# 中 是 typeof(IFillable) 在 Visual Basic 中 是 GetType(IFillable)

  调用程序使用此数组在可填充对象引用数组中遍历 例如 将填充颜色更改为粉红的 Visual Basic 代码如下所示      Dim filledList As IFillable() = drawingList GetFilledList()Dim i As IFillableFor Each i In filledListi FillBrushColor = Color HotPinkNext    用于分解出公共代码的 Helper 方法和类

  您可能注意到 Draw 和 Fill 方法有很多共同的代码 确切地说 每个类中创建笔或画笔的代码 建立 Try/Finally 块的代码以及清理笔或画笔的代码都是相同的 唯一的区别是进行绘图或填充时调用的实际方法 (由于 C# 中 using 语法非常简洁 因而多余代码的数量并不明显 )在 Visual Basic NET 中 每五行代码中可能有一行特殊的代码在所有实现中都是相同的

  总之 如果存在大量重复代码 就需要寻求分解出公共的代码 以便形成为所有类所共享的公共子例程 这类方法有很多 Dr GUI 非常高兴为您展示其中的两种 第一种方法仅用于类 第二种方法可用于类或接口 在本例中只用于接口   方法 公共入口点调用虚拟方法

  在第一个方法中 我们利用了类(不同于接口)可以包含代码这一事实 所以我们提供了一个用于创建笔的 Draw 方法的实现 以及一个异常处理程序和 Dispose 然后调用实际进行绘图的 abstract/MustOverride 方法 确切地说 我们更改了 DShapes 类以适应新的 Draw 方法 然后声明了新的 JustDraw 方法

  

    Public MustInherit Class DShape Draw 不是虚拟的 这似乎有些不寻常…… Draw 本应是抽象的 (MustOverride) 但此方法是绘图的框架 而不是绘图代码本身 绘图代码在 JustDraw 中完成 还请注意 这意味着同原版本相比 这些类具有 不同的接口 虽然它们完成的工作相同 Public Sub Draw(ByVal g As Graphics)Dim p = New Pen(penColor)TryJustDraw(g p)Finallyp Dispose()End TryEnd Sub 这里是需要成为多态的部分 因此是抽象的Protected MustOverride Sub JustDraw(ByVal g As Graphics _ByVal p As Pen)Protected bounding As RectangleProtected penColor As Color 还应具有属性 还应具有移动 调整大小等方法 End Class

    一个值得注意的有趣的地方 Draw 方法并不是 virtual/Overridable 因为所有派生类都将以相同的方式完成这部分绘图(如果在 Graphics 上绘图 [如本例中的定义] 则必须指派并清理笔) 因此它不需要是 virtual/Overridable

  实际上 Dr GUI 认为在本例中 Draw 不应该是 virtual/Overridable 如果确实要覆蓋 Draw 的行为(而不仅是 JustDraw 的行为) 则可以将它设置为 virtual/Overridable 但在本例中 没有理由覆蓋 Draw 的行为 如果鼓励程序员进行覆蓋还会带来隐患 他们可能不会正确处理笔 或者使用其他方法绘制对象而不是调用 JustDraw 这就违反了我们内置到类中的假设 因此 将 Draw 设置为非虚拟(顺便说一下 在 Brand J 中没有这个选项)可能会降低代码的灵活性 但会更加可靠 Dr GUI 认为在本例中 这样做非常值得

  JustDraw 的典型实现如下所示

    Protected Overrides Sub JustDraw(ByVal g As Graphics ByVal p As Pen)g DrawEllipse(p bounding)End Sub    如您所见 我们获得了所希望的简洁的派生类实现 (可填充类中的实现只是略微复杂一些 稍后会看到 )

  请注意 我们在接口中添加了一个额外的公开方法 JustDraw 除了要绘制的 Graphics 对象外 该方法还引用我们在 Draw 中创建的 Pen 对象 因为该方法需要是 abstract/MustOverride 因此必须是公开的

  这并不是一个大问题 但它确实更改了类的公开接口 所以即使这个分解出公共代码的方法非常简单方便 也应当尽可能选择其他方法以避免更改公开接口   方法 虚拟方法调用公共 helper 方法 使用回调

  在实现接口的 Fill 方法时 代码的复杂程度也很类似 每六行代码中可能有一行特殊的代码在所有实现中都是相同的 但是我们不能将公共的实现放到接口中 因为接口只是声明 它们不包含代码或数据 此外 上面列出的方法是不能接受的 因为它会更改接口 我们可能并不希望这样 或者因为是其他人创建的接口 我们根本不可能更改!

  所以 我们需要编写一个 helper 方法以设置并回调我们的类 以便进行实际的填充 对于本例 Dr GUI 将代码放在一个单独的类中 这样任何类都可以使用该代码 (如果采用该方法来实现 Draw 则可以将 helper 方法作为抽象基类中的私有方法实现 )

  暂时不进一步展开 以下是我们创建的类       请注意 该 delegate 提供的帮助仍然具有多态行为 Class FillHelperPublic Delegate Sub Filler(ByVal g As Graphics ByVal b As Brush)Shared Sub SafeFill(ByVal i As IFillable ByVal g As Graphics _ByVal f As Filler)Dim b = New SolidBrush(i FillBrushColor)Tryf(g b)Finallyb dispose()End TryEnd SubEnd Class    我们的 helper 方法调用了 SafeFill 该方法接受一个可填充对象(请注意 这里我们使用了 IFillable 接口类型 而不是 DShape 从而只能传递可填充对象) 一个要在其上进行绘图的 Graphics 和一个称为 delegate 的私有变量 我们可以将 delegate 视为一个对方法(而不是对象)的引用 如果您经常使用 C 或 C++ 编程 则可以将其视为具有类型安全特性的函数指针 可以将 delegate 设置为指向任何具有相同参数类型和返回值的方法 无论是实例方法还是 static/Shared 方法 将 delegate 设置为指向相应的方法后(例如在调用 SafeFill 时) 我们可以通过 delegate 间接调用该方法 (顺便说一下 Brand J 中没有 delegate 这时如果使用此方法 会非常困难并且很不灵活)

  delegate 类型 Filler 的声明位于类声明之上 它被声明为一个不返回任何内容(在 Visual Basic NET 中是一个 Sub)并且将 Graphics 和 Brush 作为参数传递的方法 我们会在将来的专栏中深入讨论 delegate

  SafeFill 的操作非常简单 它指派画笔并将 Try/Finally 和 Dispose 设置为公共代码 它通过调用我们作为参数接收的 delegate 所引用的方法进行各种操作 f(g b)

  要使用这个类 需要向可填充对象类中添加一个可以通过 delegate 调用的方法 并确保将该方法的引用(地址)传递到 SafeFill 我们将在接口的 Fill 实现中调用 SafeFill 以下是 DFilledCircle 的代码

  

    Public Sub Fill(ByVal g As Graphics) Implements IFillable FillFillHelper SafeFill(Me g AddressOf JustFill)End SubPrivate Sub JustFill(ByVal g As Graphics ByVal b As Brush)g FillEllipse(b bounding)End Sub

    这样 当需要填充对象时 便在该对象上调用 IFillable Fill 它将调用我们的 Fill 方法 而 Fill 方法调用 FillHelper SafeFill 后者传递一个对我们的可填充对象的引用 所传递的要在其上进行绘图的 Graphics 对象以及一个对实际完成填充的方法的引用 在本例中 该方法是私有的 JustFill 方法

  然后 SafeFill 通过 delegate JustFill 方法来设置画笔和调用 JustFill 方法通过调用 Graphics FillEllipse 进行填充并返回值 SafeFill 将清理画笔并返回到 Fill Fill 再返回到调用者

  最后是 JustDraw 它和原始版本中的 Draw 很类似 因为我们都调用了 Fill 并调用了基类的 Draw 方法(这是我们以前所做的) 以下是相关代码

    Protected Overrides Sub JustDraw(ByVal g As Graphics ByVal p As Pen)Fill(g)MyBase JustDraw(g p)End Sub    请记住 指派画笔和笔的复杂之处在于它在 helper 函数中的处理 在 Draw 中 它位于基类中 在 Fill 中 它位于 helper 类中

  如果您认为这比以前复杂了 那么确实如此 如果您认为由于额外的调用和需要处理 delegate 速度比以前缓慢了 也确实如此 在生活中总是有很多东西需要进行权衡

  那么 这样做值得吗?也许值得 这取决于公共代码的复杂程度 以及该代码需要重复的次数 也就是说 需要权衡 如果我们决定删除 Try/Finally 而只在完成绘图后清理笔和画笔 代码便会非常简单 这些方法也就用不上 并且在 C# 中 using 语句非常简洁 我们也不必费神使用这些方法 Dr GUI 认为 在 Visual Basic 中使用 Try/Finally 时 可以使用 也可以不使用这些方法 这里旨在向大家展示这些方法 以便在遇到具有大量公共代码的情况时使用

  维护两个列表

  因为我们要改变对象的填充颜色以实现 Change fill to hot pink 按钮 因此维护了两个可绘制对象列表 一个列表是全部对象 另一个列表是可填充对象 我们为这两个列表都使用了 ArrayList 类 ArrayList 对象包含一组 Object 引用 这样一个 ArrayList 可以包含系统中任何类型的混合

  这实际上并没有什么帮助 我们希望 ArrayList 仅仅包括可绘制/可填充对象 为此 我们将 ArrayList 对象设为私有 然后将向列表添加对象的过程设为一个方法 该方法只接受一个 DShape

  当使用 Add 方法向列表中添加对象时 我们将所有对象添加到 wholeList 中 然后检查对象是否还应添加到 filledList 集合中

  请记住 Add 方法(以及列表)具有类型安全特性 它只接受 DShape(或者从 DShape 派生的类型 例如我们在上面创建的所有类型) 您不能将整数或字符串添加到列表中 这样我们便可以知道这个列表只包含可绘制对象 能够确知这一点是很方便的!

  绘制项

  我们还有一个 DrawList 方法 用于在它作为参数传递的 Graphics 对象上绘制列表中的对象 此方法具有两种情况 如果列表为空 它绘制一个字符串 说明列表为空 如果列表不为空 它使用一个 for each 构造函数遍历该列表 并在每个对象上调用 Draw 实际的遍历和绘图代码再简单不过了 如下面的 Visual Basic 所示

     NET Dim d As DShapeFor Each d In wholeListd Draw(g)Next    由于列表是封装的 我们知道它具有类型安全特性 因此可以仅调用 Draw 方法而不必检查对象的类型

  返回可填充列表

  最后 我们的 Change fills to hot pink(将填充色更改为粉红)按钮需要一个对所有可填充对象的引用数组 以便更改其 FillBrushColor 属性 虽然可以编写一个方法遍历列表并将颜色更改为传入的值 但这一次 Dr GUI 选择了返回一个对象引用数组 幸运的是 ArrayList 类具有一个 ToArray 方法 利用它可以创建一个传递数组 该方法获取我们需要的数组元素类型 从而可以传递回所需的类型 IFillable 数组

cha138/Article/program/net/201311/12153

相关参考

知识大全 ASP.NET 窗体间传值实现方法

ASP.NET窗体间传值实现方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  假设Parent

知识大全 ASP.NET 窗体间传值的方法

ASP.NET窗体间传值的方法  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!这篇文章介绍了ASPN

知识大全 使用反射将业务对象绑定到 ASP.NET 窗体控件

使用反射将业务对象绑定到ASP.NET窗体控件  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  引

知识大全 asp.net 中实现窗体两边的浮动条

  javascript   第一个  <SCRIPTsrc=js/showjs></SCRIPT>  showjs代码如下  /****&nbs

知识大全 结合JavaScript与ASP.NET Web窗体进行程序开发

结合JavaScript与ASP.NETWeb窗体进行程序开发  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来

知识大全 .Net中掌握Windows窗体间数据交互(2)

.Net中掌握Windows窗体间数据交互(2)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 .Net中掌握Windows窗体间数据交互(1)

.Net中掌握Windows窗体间数据交互(1)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  

知识大全 .net中Windows窗体间的数据交互(一)

.net中Windows窗体间的数据交互(一)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  W

知识大全 基于窗体的身份验证

ASP.Net:基于窗体的身份验证  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  基于窗体的验证

知识大全 asp.net基础小结

  一动态网页和静态网页  起初看到这两个概念会以为动态网页就是网页带有flash的页面而静态网页就是不会动的网页现在看来这种理解是错误的大错特错所谓的动态网页呢其实是指网页和服务器有交互的服务器中的