Microsoft® ASP.NET 为开发人员提供了一种适用于 Web 开发的、功能最为强大的新工具:服务器控件。服务器控件使开发人员能够在短时间内开发出响应速度快而且功能强大的 Web 应用程序,所需的时间与在典型的 ASP 中创建类似应用程序的时间差不多。
ASP.NET 服务器控件之所以能够提供生产效率,关键原因之一在于它为 Microsoft Visual Studio® .NET 开发环境中的服务器控件提供了丰富的设计时支持。开发人员可以将服务器控件从 Visual Studio .NET 工具箱拖放到页面上,通过 Properties(属性)窗口访问它们的属性,然后在 Visual Studio HTML 编辑器以及 ASP.NET 页面的内含代码的类中利用 Microsoft IntelliSense® 语句完成功能。这些设计时功能为 Web 开发带来了快速应用程序开发 (RAD) 工具,而这些工具已被 Microsoft Visual Basic® 开发人员使用了多年。
ASP.NET 还使开发人员能够通过创建自定义服务器控件以封装大量可重复使用的用户界面特定的代码(例如登录或注册表单),来进一步提高生产效率。尽管开发人员已经开始意识到开发自定义控件的重要性,但许多人可能还没有意识到还能在控件中利用 Visual Studio 设计时支持的强大功能,使这些控件能够像 ASP.NET 中的内置控件那样易于使用。本文将介绍 Microsoft .NET Framework 和 Visual Studio .NET 提供的设计时支持的类型,并向开发人员介绍如何构建利用这种支持的控件。
设计时支持的类型
针对 Visual Studio .NET 中的服务器控件,有五种不同的设计时支持。它们是:
内含代码的类中的 IntelliSense
设计视图中的属性浏览器支持
工具箱支持
HTML 视图中的属性浏览器支持
HTML 编辑器中的 IntelliSense
这些设计时支持类型是由几个不同的机制提供的。内含代码的类中的 IntelliSense 由 IDE 启用,IDE 为您的控件读取元数据以确定控件所提供的属性和方法及其类型和参数。要启用内含代码的类中的 IntelliSense,只需对您的控件进行编写和编译,然后将其程序集放到使用该控件的应用程序的 bin 子目录中。
Visual Studio .NET 编辑器设计视图中的属性浏览器支持通过以下两个途径提供:将该类型与某个属性相关联和/或将元数据特性与该属性相关联。将元数据特性(下文简称为特性)添加到您的代码中,用于标识属性的类别、提供属性说明以及在需要时指定首选编辑器。有些类型的属性(如 System.Drawing.Color)会自动映射到 Visual Studio .NET 中的相应编辑器中。
Visual Studio .NET 的 HTML 视图中的 IntelliSense 和属性浏览器支持通过使用一种 XSD 架构进行提供,该架构用于描述与控件相关联的类型,它使用称为 Visual Studio 注释的文本修饰指定控件的首选编辑器和其他首选项。
最后,您可以通过结合特性和带有特定属性的自定义位图来支持从 Visual Studio .NET 工具箱拖放控件。
Blog 控件示例
用于说明 Visual Studio .NET 中的设计时功能的控件称作“Blog 控件”,如本文末尾的列表 1 所示。该控件提供利用 XML 作为存储介质的简单 Web 日志功能。Web 日志通常称为 Blog,它实际上是一个 Web 页面,供人们在上面张贴有关日常生活、世态百象、时事政治或人们所关心的其他问题的定期观察报告或评论。Blog 条目是通过 Web 浏览器添加的。
Blog 控件非常简单明了,它利用控件组合向浏览器提供输出。在组合控件中,CreateChildControls 方法(由 ASP.NET 运行时自动调用)会被重写,利用此方法,我们可以创建构成自定义控件 UI 的控件,并将它们添加到控件的“控件”集合中。此外,该丶拱糜谙允竞吞砑?Blog 以及当 XML Blog 存储文件不存在时创建一个这样的文件的逻辑。该控件的几个公共属性需要开发人员在设计时进行设置,其中包括在添加新 Blog 时该控件将重定向到的页面的 URL、与新 Blog 关联的电子邮件地址、控件模式(显示或添加)以及各 Blog 条目之间的分隔线的颜色。图 1 所示为正在运行的 Blog 控件。Add Blog(添加 Blog)超链接由 ASP.NET 超链接控件提供,独立于 Blog 控件。BlogClient.aspx 的代码如列表 2 所示。BlogClient.aspx 的 codebehind 类如列表 3 所示,它提供单击 Add Blog(添加 Blog)链接时更改 Blog 模式的逻辑。
图 1:运行时的 Blog 控件
图 2 所示为设计时基本 Blog 控件的外观。请注意,虽然列出了属性,但并未分类。
图 2:设计时的 Blog 控件
添加设计时支持
虽然在 Web 窗体页上使用 Blog 控件非常简单,但并不是很直观。例如,如果没有相关文档,使用 Blog 控件的人就无法知道 Mode 属性的有效值只能是 Display 或 Add。如果未将 Add 模式的相关信息明确地告诉使用该控件的开发人员,他们就很难自己发现并使用这种模式。
遗憾的是,语句完成功能的自动支持并没有扩展到编辑 Web 窗体页时的设计视图或 HTML 视图,而且 Visual Studio 也没有提供不需要额外的控件工作就能在属性浏览器中查看和编辑属性的内置支持。更复杂的是,要在 Web 窗体编辑器的属性浏览器和设计视图中支持 IntelliSense,需要采用一种方法,要在该编辑器的 HTML 视图中支持 IntelliSense,则需要采用另一种方法。
要在设计视图中支持属性浏览,所需的方法是通过特性告诉 Visual Studio .NET 如何处理属性。要在 HTML 视图中支持语句完成和属性浏览,需要生成一个自定义 XSD 架构以描述控件中的类型。我们将在下文讨论这两种方法。
设计视图和元数据特性
Visual Studio .NET 为使用拖放技术的动态控件设计和修改提供了丰富的支持,同时还提供了属性浏览器之类的工具以及相关的设计器(例如颜色选择器)。对这些工具的支持是通过一系列特性提供的,您可以将这些特性添加到您的控件中。这些特性用于告诉 Visual Studio IDE 是否在属性浏览器中显示控件的属性、属性所属的类型以及应使用哪个设计器设置属性的值。
将控件添加到工具箱中后,可以通过双击该控件或将其从工具箱中拖放到 Web 窗体页上,将其添加到 Web 窗体页中。无论何种情况,Visual Studio .NET 都会自动插入正确的 @Register 指令(包括基于程序集级别的特性设置 TagPrefix),还将使用 ToolBoxData 属性中指定的标记名为该控件生成一组标记。
添加设计器
正如前文所述,Blog 控件在 Web 窗体编辑器的设计视图中没有任何可视界面。这使得选择页面上的控件很困难,更难以理解控件在运行时的外观。为了解决这个问题,我们可以添加设计器支持,使设计时的 HTML 在外观上接近于运行时的 Blog 控件。请注意,您还可以生成可以完整再现控件运行时输出的设计器,但此操作相当复杂,而且超出了本文的讨论范围。
所有服务器控件设计器都是从类 System.Web.UI.Design.ControlDesigner 派生而来,该类提供了大量方法,您可以重写这些方法为您的控件提供设计时渲染。以下代码简单重写了 GetDesignTimeHtml 方法,返回设计时显示的简单 HTML。请注意,该示例显示了 Blog 控件的整个设计器类,您可以简单地将其添加到现有的 Blog_DT.vb 类文件中。
Public Class BlogDesigner
Inherits ControlDesigner
Public Overrides Function GetDesignTimeHtml() As String
Return "<h1>Blog</h1><hr/><hr/>"
End Function
End Class
<Description("简单 Blog 控件。支持显示 " & _
"Web 日志/来自 XML 文件的新条目。"), _
Designer("BlogControl.BlogDesigner"), _
ToolboxData("<{0}:Blog_DT runat=server></{0}:Blog_DT>")> _
Public Class Blog_DT
Inherits Panel
Implements INamingContainer
如您所见,BlogDesigner 类非常简单,但它为控件在 Web 窗体页上的设计时外观添加了大量内容,如图 7 所示。
图 7:添加设计时渲染
列表 4 显示了 Blog 控件的代码,它已经使用特性进行了更新,以启用设计视图和属性浏览器中的控件设计时支持。请注意,该示例添加了多条 using 指令,以导入支持我们使用的特性和设计器类所需要的命名空间。这个新列表还添加了一个用于 Mode 属性值的枚举。
HTML 视图支持:自定义架构和 Visual Studio 注释
尽管前文所述的特性帮助我们为 Blog 控件提供了设计时支持,但这里遗漏了一个重要的问题:在 Web 窗体编辑器的 HTML 视图中添加标记和特性的 IntelliSense 支持。对于那些认为在 HTML 环境中工作比在“所见即所得”风格的环境中工作更舒适的开发人员来说,这是一个极大的疏忽。
因为 Web 窗体编辑器的 HTML 视图使用 XSD 架构决定在 Web 窗体页上提供哪些元素和特性,所以为了纠正这一问题,我们需要提供一个描述 Blog 控件及其所支持的特性的 XSD 架构。也可以在该架构中添加注释,告诉 Visual Studio .NET 各种元素的有关信息以及我们所希望的元素行为。
列表 5 包含 Blog 控件特定的 XSD 架构的部分内容。实际的架构文件(可从本文的示例代码中获得)还包含面板控件(Blog_DT 控件就是由它派生的)的类型定义以及其他必需的特性和类型定义。这些定义是从为内置 ASP.NET 服务器控件创建的 asp.xsd 架构文件中复制的。
本文介绍了 Visual Studio .NET 中适用于 ASP.NET 服务器控件的设计时支持,还说明了开发人员如何在自己的自定义控件中利用这一支持功能。虽然在控件中添加设计时支持相对简明,但要充分利用这些功能却需要掌握多种不同的技巧。特别欠缺的知识领域就是如何将自定义 XSD 架构绑定到页面上。在撰写本文时,还不具备将页面与控件 XSD 架构连接起来所需的 xmlns 特性的内置支持。所以,还需要手动添加这个特性。希望以后的 Visual Studio .NET 版本能够自动完成这一过程。
本文中的示例代码包含一个适用于 Blog 控件基础版和设计时支持版的 Visual Studio .NET 项目,还包含一个说明如何使用每个控件的客户端项目。要运行 BlogControlClient 项目,您需要在 IIS 中创建一个虚拟目录 BlogControlClient,然后将其映射到硬盘驱动器上用于保存 BlogControlClient 项目文件夹的位置。
真诚地感谢 Microsoft Visual Studio .NET 团队的 Rob Caron,他在我编写自定义 XSD 架构的创建和绑定过程中给予了极大的帮助。
作者介绍
G. Andrew Duthie 是 Graymad Enterprises, Inc.(英文)的创始人和负责人,该公司提供 Microsoft Web 开发技术的培训和咨询服务。自从 Active Server Pages 问世以来,Andrew 一直从事多层 Web 应用程序的开发工作。他编写了大量有关 ASP.NET 的著作,其中包括:《Microsoft ASP.NET Step By Step》、《Microsoft ASP.NET Programming with Microsoft Visual Basic》和《ASP.NET in a Nutshell》。Andrew 经常在一些重大活动中发表演讲,这些活动包括“Software Development”、“Dev-Connections family of conferences”、“Microsoft Developer Days”以及“VSLive!”。他还作为 International .NET Association (INETA)(英文)Speaker's Bureau 成员在 .NET 用户组上发表了演讲。您可以从其公司的 Web 站点 Graymad Enterprises, Inc.(英文)上了解到有关 Andrew 的更多信息。
本文是根据《ASP.NET in a Nutshell》第二版(ISBN:0596001169)改编而成,其作者包括 G. Andrew Duthie 和 Matthew MacDonald,由 O'Reilly & Associates, Inc. 于 2003 年出版。
代码列表
列表 1:Blog.vb
'supports Color structure
Imports System.Drawing
'支持 StreamWriter 类型
Imports System.IO
Imports System.Web.UI
'支持使用 HTML 控件
Imports System.Web.UI.HtmlControls
'支持使用 Web 控件
Imports System.Web.UI.WebControls
Public Class Blog
Inherits Panel
Implements INamingContainer
Protected BlogDS As DataSet
Protected TitleTB As TextBox
Protected BlogText As TextBox
Private _addRedirect As String
Private _email As String
Private _mode As String
Private _separatorColor As Color = Color.Black
Public Property AddRedirect() As String
Get
Return Me._addRedirect
End Get
Set(ByVal Value As String)
Me._addRedirect = Value
End Set
End Property
Public Property Email() As String
Get
Return Me._email
End Get
Set(ByVal Value As String)
Me._email = Value
End Set
End Property
Public Property Mode() As String
Get
Return Me._mode
End Get
Set(ByVal Value As String)
Me._mode = Value
End Set
End Property
Public Property SeparatorColor() As Color
Get
Return Me._separatorColor
End Get
Set(ByVal Value As Color)
Me._separatorColor = Value
End Set
End Property
Protected Overrides Sub OnInit(ByVal e As EventArgs)
LoadData()
MyBase.OnInit(e)
End Sub
Protected Overrides Sub CreateChildControls()
If Not Me._mode = "Add" Then
DisplayBlogs()
Else
NewBlog()
End If
End Sub
Protected Sub LoadData()
BlogDS = New DataSet()
Try
BlogDS.ReadXml(Page.Server.MapPath("Blog.xml"))
Catch fnfEx As FileNotFoundException
CreateBlankFile()
LoadData()
End Try
End Sub
Protected Sub DisplayBlogs()
Dim BlogDate As DateTime
Dim CurrentDate As DateTime = New DateTime()
Dim BlogRows As DataRowCollection = _
BlogDS.Tables(0).Rows
Dim BlogDR As DataRow
For Each BlogDR In BlogRows
Dim BDate As String = BlogDR("date").ToString()
BlogDate = New DateTime _
(Convert.ToInt32(BDate.Substring(4, 4)), _
Convert.ToInt32(BDate.Substring(0, 2)), _
Convert.ToInt32(BDate.Substring(2, 2)))
If Not CurrentDate = BlogDate Then
Dim TempDate As Label = New Label()
TempDate.Text = BlogDate.ToLongDateString()
TempDate.Font.Size = FontUnit.Large
TempDate.Font.Bold = True
Me.Controls.Add(TempDate)
Me.Controls.Add _
(New LiteralControl("<br/><br/>"))
CurrentDate = BlogDate
End If
Dim Anchor As HtmlAnchor = New HtmlAnchor()
Anchor.Name = "#" & BlogDR("anchorID").ToString()
Me.Controls.Add(Anchor)
Dim Title As Label = New Label()
Title.Text = BlogDR("title").ToString()
Title.Font.Size = FontUnit.Larger
Title.Font.Bold = True
Me.Controls.Add(Title)
Me.Controls.Add(New LiteralControl("<p>"))
Dim BlogText As LiteralControl = _
New LiteralControl("<div>" & _
BlogDR("text").ToString() & "</div>")
Me.Controls.Add(BlogText)
Me.Controls.Add(New LiteralControl("</p>"))
Dim Email As HyperLink = New HyperLink()
Email.NavigateUrl = "mailto:" & _
BlogDR("email").ToString()
Email.Text = "E-mail me"
Me.Controls.Add(Email)
Me.Controls.Add(New LiteralControl(" | "))
Dim AnchorLink As HyperLink = New HyperLink()
AnchorLink.NavigateUrl = _
Page.Request.Url.ToString() & "#" & _
BlogDR("anchorID").ToString()
AnchorLink.Text = "Link"
Me.Controls.Add(AnchorLink)
Me.Controls.Add(New _
LiteralControl("<hr color='" & _
ColorTranslator.ToHtml(_separatorColor) & _
"' width='100%'/><br/>"))
Next
End Sub
Protected Sub NewBlog()
Dim Title As Label = New Label()
Title.Text = "Create New Blog"
Title.Font.Size = FontUnit.Larger
Title.Font.Bold = True
Me.Controls.Add(Title)
Me.Controls.Add(New LiteralControl("<br/><br/>"))
Dim TitleLabel As Label = New Label()
TitleLabel.Text = "Title: "
TitleLabel.Font.Bold = True
Me.Controls.Add(TitleLabel)
TitleTB = New TextBox()
Me.Controls.Add(TitleTB)
Me.Controls.Add(New LiteralControl("<br/>"))
Dim BlogTextLabel As Label = New Label()
BlogTextLabel.Text = "Text: "
BlogTextLabel.Font.Bold = True
Me.Controls.Add(BlogTextLabel)
BlogText = New TextBox()
BlogText.TextMode = TextBoxMode.MultiLine
BlogText.Rows = 10
BlogText.Columns = 40
Me.Controls.Add(BlogText)
Me.Controls.Add(New LiteralControl("<br/>"))
Dim Submit As Button = New Button()
Submit.Text = "Submit"
AddHandler Submit.Click, AddressOf Me.Submit_Click
Me.Controls.Add(Submit)
End Sub
Protected Sub Submit_Click(ByVal Sender As Object, _
ByVal e As EventArgs)
EnsureChildControls()
AddBlog()
End Sub
Protected Sub AddBlog()
Dim NewBlogDR As DataRow
NewBlogDR = BlogDS.Tables(0).NewRow()
NewBlogDR("date") = FormatDate(DateTime.Today)
NewBlogDR("title") = TitleTB.Text
NewBlogDR("text") = BlogText.Text
NewBlogDR("anchorID") = Guid.NewGuid().ToString()
NewBlogDR("email") = _email
BlogDS.Tables(0).Rows.InsertAt(NewBlogDR, 0)
BlogDS.WriteXml(Page.Server.MapPath("Blog.xml"))
Page.Response.Redirect(_addRedirect)
End Sub
Protected Function FormatDate(ByVal dt As DateTime) _
As String
Dim retString As String
retString = String.Format("{0:D2}", dt.Month)
retString &= String.Format("{0:D2}", dt.Day)
retString &= String.Format("{0:D2}", dt.Year)
Return retString
End Function
Public Sub CreateBlankFile()
Dim NewXml As StreamWriter = _
File.CreateText(Page.Server.MapPath("Blog.xml"))
NewXml.WriteLine("<blogs>")
NewXml.WriteLine _
(" <!-- blog field describes a single blog -->")
NewXml.WriteLine(" <blog>")
NewXml.WriteLine(" <!-- date field contains" & _
" the creation date of the blog -->")
NewXml.WriteLine(" <date>" & _
FormatDate(DateTime.Today) & "</date>")
NewXml.WriteLine _
(" <title>Temporary Blog</title>")
NewXml.WriteLine(" <!-- text field " & _
"should contain the blog text, including any " & _
"desired HTML tags -->")
NewXml.WriteLine(" <text>This entry " & _
"indicates that the file blog.xml was not " & _
"found.A default version of this file has " & _
"been created for you.You can modify the " & _
"fields in this file as desired.If you set " & _
"the Blog control to add mode (add the " & _
"attribute mode='add' to the control's " & _
"declaration), the control will " & _
"automatically populate the XML file when " & _
"you submit the form.</text>")
NewXml.WriteLine(" <!-- anchorID field " & _
"will be autopopulated by the control -->")
NewXml.WriteLine(" <anchorID></anchorID>")
NewXml.WriteLine(" <!-- email field should" & _
" contain the email address for feedback -->")
NewXml.WriteLine(" <email>change this to a " & _
"valid email address</email>")
NewXml.WriteLine(" </blog>")
NewXml.WriteLine("</blogs>")
NewXml.Close()
End Sub
End Class
Imports BlogControl
Public Class WebForm1
Inherits System.Web.UI.Page
Protected WithEvents Link1 As _
System.Web.UI.WebControls.HyperLink
Protected WithEvents Link2 As _
System.Web.UI.WebControls.HyperLink
Protected WithEvents Blog1 As BlogControl.Blog
Private Sub Page_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles MyBase.Load
If Request.QueryString("mode") = "add" Then
Blog1.Mode = "Add"
Link1.Visible = False
Link2.Visible = False
Else
Blog1.Mode = "Display"
Link1.Visible = True
Link2.Visible = True
End If
End Sub
End Class
列表 4:Blog_DT.vb
'支持设计时特性
Imports System.ComponentModel
'支持颜色结构
Imports System.Drawing
'支持 UITypeEditor 类型
Imports System.Drawing.Design
'支持 StreamWriter 类型
Imports System.IO
Imports System.Web.UI
'支持 ControlDesigner 类型
' 请注意,必须添加程序集
' System.Design 的引用,才能导入此命名空间
Imports System.Web.UI.Design
'支持使用 HTML 控件
Imports System.Web.UI.HtmlControls
'支持使用 Web 控件
Imports System.Web.UI.WebControls
<Assembly: TagPrefix("BlogControl", "BlogControl")>
Public Enum BlogMode
Add
Display
End Enum
<Description("Simple Blog control.Supports display " & _
"of Web log / news items from an XML file."), _
Designer("BlogControl.BlogDesigner"), _
ToolboxData("<{0}:Blog_DT runat=server></{0}:Blog_DT>")> _
Public Class Blog_DT
Inherits Panel
Implements INamingContainer
Protected BlogDS As DataSet
Protected TitleTB As TextBox
Protected BlogText As TextBox
Private _addRedirect As String
Private _email As String
Private _mode As BlogMode
Private _separatorColor As Color = Color.Black
<Browsable(True), _
Category("Behavior"), _
Description("URL to which the page should redirect after successful submission of a new Blog entry."), _
Editor("System.Web.UI.Design.UrlEditor", _
GetType(UITypeEditor))> _
Public Property AddRedirect() As String
Get
Return Me._addRedirect
End Get
Set(ByVal Value As String)
Me._addRedirect = Value
End Set
End Property
<Browsable(True), _
Category("Behavior"), _
Description("Email address the control will use for listing in new Blog entries.")> _
Public Property Email() As String
Get
Return Me._email
End Get
Set(ByVal Value As String)
Me._email = Value
End Set
End Property
<Browsable(True), _
Category("Behavior"), _
Description("Controls whether existing Blogs are displayed, or fields for creating a new Blog entry.")> _
Public Property Mode() As BlogMode
Get
Return Me._mode
End Get
Set(ByVal Value As BlogMode)
Me._mode = Value
End Set
End Property
<Browsable(True), _
Category("Appearance"), _
Description("Controls the color of the line that separates Blog entries when in display mode.")> _
Public Property SeparatorColor() As Color
Get
Return Me._separatorColor
End Get
Set(ByVal Value As Color)
Me._separatorColor = Value
End Set
End Property
Protected Overrides Sub OnInit(ByVal e As EventArgs)
LoadData()
MyBase.OnInit(e)
End Sub
Protected Overrides Sub CreateChildControls()
If Not Me._mode = BlogMode.Add Then
DisplayBlogs()
Else
NewBlog()
End If
End Sub
Protected Sub LoadData()
BlogDS = New DataSet()
Try
BlogDS.ReadXml(Page.Server.MapPath("Blog.xml"))
Catch fnfEx As FileNotFoundException
CreateBlankFile()
LoadData()
End Try
End Sub
Protected Sub DisplayBlogs()
Dim BlogDate As DateTime
Dim CurrentDate As DateTime = New DateTime()
Dim BlogRows As DataRowCollection = _
BlogDS.Tables(0).Rows
Dim BlogDR As DataRow
For Each BlogDR In BlogRows
Dim BDate As String = BlogDR("date").ToString()
BlogDate = New DateTime _
(Convert.ToInt32(BDate.Substring(4, 4)), _
Convert.ToInt32(BDate.Substring(0, 2)), _
Convert.ToInt32(BDate.Substring(2, 2)))
If Not CurrentDate = BlogDate Then
Dim TempDate As Label = New Label()
TempDate.Text = BlogDate.ToLongDateString()
TempDate.Font.Size = FontUnit.Large
TempDate.Font.Bold = True
Me.Controls.Add(TempDate)
Me.Controls.Add _
(New LiteralControl("<br/><br/>"))
CurrentDate = BlogDate
End If
Dim Anchor As HtmlAnchor = New HtmlAnchor()
Anchor.Name = "#" + BlogDR("anchorID").ToString()
Me.Controls.Add(Anchor)
Dim Title As Label = New Label()
Title.Text = BlogDR("title").ToString()
Title.Font.Size = FontUnit.Larger
Title.Font.Bold = True
Me.Controls.Add(Title)
Me.Controls.Add(New LiteralControl("<p>"))
Dim BlogText As LiteralControl = _
New LiteralControl("<div>" & _
BlogDR("text").ToString() & "</div>")
Me.Controls.Add(BlogText)
Me.Controls.Add(New LiteralControl("</p>"))
Dim Email As HyperLink = New HyperLink()
Email.NavigateUrl = "mailto:" & _
BlogDR("email").ToString()
Email.Text = "E-mail me"
Me.Controls.Add(Email)
Me.Controls.Add(New LiteralControl(" | "))
Dim AnchorLink As HyperLink = New HyperLink()
AnchorLink.NavigateUrl = _
Page.Request.Url.ToString() & "#" & _
BlogDR("anchorID").ToString()
AnchorLink.Text = "Link"
Me.Controls.Add(AnchorLink)
Me.Controls.Add _
(New LiteralControl("<hr color='" & _
ColorTranslator.ToHtml(_separatorColor) & _
"' width='100%'/><br/>"))
Next
End Sub
Protected Sub NewBlog()
Dim Title As Label = New Label()
Title.Text = "Create New Blog"
Title.Font.Size = FontUnit.Larger
Title.Font.Bold = True
Me.Controls.Add(Title)
Me.Controls.Add(New LiteralControl("<br/><br/>"))
Dim TitleLabel As Label = New Label()
TitleLabel.Text = "Title: "
TitleLabel.Font.Bold = True
Me.Controls.Add(TitleLabel)
TitleTB = New TextBox()
Me.Controls.Add(TitleTB)
Me.Controls.Add(New LiteralControl("<br/>"))
Dim BlogTextLabel As Label = New Label()
BlogTextLabel.Text = "Text: "
BlogTextLabel.Font.Bold = True
Me.Controls.Add(BlogTextLabel)
BlogText = New TextBox()
BlogText.TextMode = TextBoxMode.MultiLine
BlogText.Rows = 10
BlogText.Columns = 40
Me.Controls.Add(BlogText)
Me.Controls.Add(New LiteralControl("<br/>"))
Dim Submit As Button = New Button()
Submit.Text = "Submit"
AddHandler Submit.Click, AddressOf Me.Submit_Click
Me.Controls.Add(Submit)
End Sub
Protected Sub Submit_Click(ByVal Sender As Object, _
ByVal e As EventArgs)
EnsureChildControls()
AddBlog()
End Sub
Protected Sub AddBlog()
Dim NewBlogDR As DataRow
NewBlogDR = BlogDS.Tables(0).NewRow()
NewBlogDR("date") = FormatDate(DateTime.Today)
NewBlogDR("title") = TitleTB.Text
NewBlogDR("text") = BlogText.Text
NewBlogDR("anchorID") = Guid.NewGuid().ToString()
NewBlogDR("email") = _email
BlogDS.Tables(0).Rows.InsertAt(NewBlogDR, 0)
BlogDS.WriteXml(Page.Server.MapPath("Blog.xml"))
Page.Response.Redirect(_addRedirect)
End Sub
Protected Function FormatDate(ByVal dt As DateTime) As String
Dim retString As String
retString = String.Format("{0:D2}", dt.Month)
retString &= String.Format("{0:D2}", dt.Day)
retString &= String.Format("{0:D2}", dt.Year)
Return retString
End Function
Public Sub CreateBlankFile()
Dim NewXml As StreamWriter = _
File.CreateText(Page.Server.MapPath("Blog.xml"))
NewXml.WriteLine("<blogs>")
NewXml.WriteLine _
(" <!-- blog field describes a single blog -->")
NewXml.WriteLine(" <blog>")
NewXml.WriteLine(" <!-- date field contains" & _
" the creation date of the blog -->")
NewXml.WriteLine(" <date>" & _
FormatDate(DateTime.Today) & "</date>")
NewXml.WriteLine _
(" <title>Temporary Blog</title>")
NewXml.WriteLine(" <!-- text field " & _
"should contain the blog text, including any " & _
"desired HTML tags -->")
NewXml.WriteLine(" <text>This entry " & _
"indicates that the file blog.xml was not " & _
"found.A default version of this file has " & _
"been created for you.You can modify the " & _
"fields in this file as desired.If you set " & _
"the Blog control to add mode (add the " & _
"attribute mode='add' to the control's " & _
"declaration), the control will " & _
"automatically populate the XML file when " & _
"you submit the form.</text>")
NewXml.WriteLine(" <!-- anchorID field " & _
"will be autopopulated by the control -->")
NewXml.WriteLine(" <anchorID></anchorID>")
NewXml.WriteLine(" <!-- email field should" & _
" contain the email address for feedback -->")
NewXml.WriteLine(" <email>change this to a " & _
"valid email address</email>")
NewXml.WriteLine(" </blog>")
NewXml.WriteLine("</blogs>")
NewXml.Close()
End Sub
End Class
Public Class BlogDesigner
Inherits ControlDesigner
Public Overrides Function GetDesignTimeHtml() As String
Return "<h1>Blog</h1><hr/><hr/>"
End Function
End Class
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架