
Creating Custom Controls and Designers
In this section, you create three basic Web server controls and an associated custom control designer for each of them.
To create a file for the code
In an editor, create a new file named SimpleControlDesigners with the appropriate extension for the language you are working in. For example, in Visual Studio 2005, create a new class file named SimpleControlDesigners.vb or SimpleControlDesigners.cs.
Add the following namespace references that are necessary for working with the designer classes. Also add a namespace to contain your controls and the associated designers.
Imports System
Imports System.ComponentModel
Imports System.ComponentModel.Design
Imports System.Drawing
Imports System.Web.UI
Imports System.Web.UI.Design
Imports System.Web.UI.Design.WebControls
Imports System.Web.UI.WebControls
Namespace Samples.AspNet.VB.Controls
End Namespace
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Web.UI;
using System.Web.UI.Design;
using System.Web.UI.Design.WebControls;
using System.Web.UI.WebControls;
namespace Samples.AspNet.CS.Controls
{
}
Save the file.
Now you are ready to create a composite Web server control and an associated designer. A designer can be in the same assembly as the control or in a different one; in this walkthrough, you create them in the same code file and assembly for convenience.
To create a composite control and an associated designer
Within the namespace you declared in the SimpleControlDesigners file, create a public declaration for a composite control class that inherits from CompositeControl, as shown in the following code example.
Public Class SimpleCompositeControl
Inherits CompositeControl
End Class
public class SimpleCompositeControl : CompositeControl
{
}
Add the public properties shown in the following code example to the class. These will be used to create part of the UI on the Web page.
Dim _prompt As String = "Please enter your date of birth: "
Overridable Property Prompt() As String
Get
Dim o As Object
o = ViewState("Prompt")
If o Is Nothing Then
Return _prompt
Else
Return CType(o, String)
End If
End Get
Set(ByVal value As String)
ViewState("Prompt") = value
End Set
End Property
Overridable Property DOB() As DateTime
Get
Dim o As Object
o = ViewState("DOB")
If o Is Nothing Then
Return DateTime.Now
Else
Return CType(o, DateTime)
End If
End Get
Set(ByVal value As DateTime)
ViewState("DOB") = value
End Set
End Property
private String _prompt = "Please enter your date of birth: ";
public virtual String Prompt
{
get
{
object o = ViewState["Prompt"];
return (o == null) ? _prompt : (string)o;
}
set
{
ViewState["Prompt"] = value;
}
}
public virtual DateTime DOB
{
get
{
object o = ViewState["DOB"];
return (o == null) ? DateTime.Now : (DateTime)o;
}
set
{
ViewState["DOB"] = value;
}
}
Create a method to add child controls to the composite control. The following method adds two text boxes and a line break that will be visible on the Web page.
Protected Overrides Sub CreateChildControls()
Dim lab As New Label
lab.Text = Prompt
lab.ForeColor = System.Drawing.Color.Red
Me.Controls.Add(lab)
Dim lit As New Literal()
lit.Text = "<br />"
Me.Controls.Add(lit)
Dim tb As New TextBox()
tb.ID = "tb1"
tb.Text = DOB.ToString()
Me.Controls.Add(tb)
MyBase.CreateChildControls()
End Sub
protected override void CreateChildControls()
{
Label lab = new Label();
lab.Text = Prompt;
lab.ForeColor = System.Drawing.Color.Red;
this.Controls.Add(lab);
Literal lit = new Literal();
lit.Text = "<br />";
this.Controls.Add(lit);
TextBox tb = new TextBox();
tb.ID = "tb1";
tb.Text = DOB.ToString();
this.Controls.Add(tb);
base.CreateChildControls();
}
Create a simple composite control designer class that derives from CompositeControlDesigner to associate with the composite control you just created.
Although there are a variety of UI rendering features you could add to the designer, the following code example simply creates the designer and overrides a key property in the base class to prevent the control from being resized in design view.
Public Class SimpleCompositeControlDesigner
Inherits CompositeControlDesigner
' Set this property to prevent the designer from being resized.
Public Overrides ReadOnly Property AllowResize() As Boolean
Get
Return False
End Get
End Property
End Class
public class SimpleCompositeControlDesigner : CompositeControlDesigner
{
// Set this property to prevent the designer from being resized.
public override bool AllowResize
{
get { return false; }
}
}
Immediately above the class declaration for the composite control, add a Designer metadata attribute that associates the control with the designer class you just created, as shown in the following code example.
<Designer(GetType(SimpleCompositeControlDesigner))> _
Public Class SimpleCompositeControl
Inherits CompositeControl
[Designer(typeof(SimpleCompositeControlDesigner))]
public class SimpleCompositeControl : CompositeControl
Save the file.
Now that you have created a custom composite Web server control and an associated designer, you can create a second control that derives from the first. The second control differs only in that its associated designer can be resized on the design surface.
To create a resizable composite control and associated designer
Within the namespace you declared in the SimpleControlDesigners file, create a public declaration for a new composite control class that inherits from the SimpleCompositeControl control you created earlier. The following code example demonstrates a new declaration.
Public Class SimpleCompositeControl2
Inherits SimpleCompositeControl
End Class
public class SimpleCompositeControl2 : SimpleCompositeControl
{
}
Associate this control with the CompositeControlDesigner base class.
By default, this example creates a basic, resizable designer for the composite control.
<Designer(GetType(CompositeControlDesigner))> _
Public Class SimpleCompositeControl2
Inherits SimpleCompositeControl
End Class
[Designer(typeof(CompositeControlDesigner))]
public class SimpleCompositeControl2 : SimpleCompositeControl
{
}
Save the file.
The first two controls you created were composite controls that you associated with composite control designers. Now you will create a simple control that derives from WebControl, and associate it with a ContainerControlDesigner class. This type of designer is useful when you want to associate a designer with a single custom Web server control and provide a single editable region on the design surface. The custom control you create here does not implement any actual functionality; it exists only to show the features of the ContainerControlDesigner class.
Note: |
|---|
You could also provide this same functionality using a composite control and designer like those you created earlier. This example is intended only to show how you can use the
ContainerControlDesigner class and associate it with a WebControl control.
|
To create a Web server control and a container designer with an editable region
Within the namespace you declared in the SimpleControlDesigners file, create a public declaration for a new Web server control class, as shown in the following code example.
Public Class SimpleContainerControl
Inherits WebControl
Implements INamingContainer
End Class
public class SimpleContainerControl : WebControl, INamingContainer
{
}
Create a container control designer class to associate with the custom control. Implement two properties: a FrameStyle property to contain the style for the designer's frame, and a FrameCaption property to contain the frame's header text. These properties provide a frame for the control to be visibly rendered and selected on the design surface. The code for the designer and properties is shown in the following code example.
Note: |
|---|
The
ContainerControlDesigner class automatically handles all other aspects of rendering the custom control at design time and providing a single editable region.
|
Public Class SimpleContainerControlDesigner
Inherits ContainerControlDesigner
Dim _style As Style
' Add the caption by default.
Public Overrides ReadOnly Property FrameCaption() As String
Get
Return "A Simple ContainerControlDesigner"
End Get
End Property
Public Overrides ReadOnly Property Framestyle() As Style
Get
If _style Is Nothing Then
_style = New Style()
_style.Font.Name = "Verdana"
_style.Font.Size = New FontUnit("XSmall")
_style.BackColor = Color.LightBlue
_style.ForeColor = Color.Black
End If
Return _style
End Get
End Property
End Class
public class SimpleContainerControlDesigner : ContainerControlDesigner
{
private Style _style = null;
// Add the caption by default. Note that the caption
// will only appear if the Web server control
// allows child controls rather than properties.
public override string FrameCaption
{
get
{
return "A Simple ContainerControlDesigner";
}
}
public override Style FrameStyle
{
get
{
if (_style == null)
{
_style = new Style ();
_style.Font.Name = "Verdana";
_style.Font.Size = new FontUnit ("XSmall");
_style.BackColor = Color.LightBlue;
_style.ForeColor = Color.Black;
}
return _style;
}
}
}
Associate the designer with the control. Immediately above the class declaration for the Web server control, add the Designer metadata attribute. Note that in this case, as shown in the following code example, you also add the ParseChildren attribute with a false parameter. This tells the design-time parser to treat the inner contents of controls as child controls, rather than as properties. In this case, you want to treat the inner contents of this control as child controls so that you can actually drag other server controls into the editable region at design time, and edit their properties as well.
<Designer(GetType(SimpleContainerControlDesigner))> _
<ParseChildren(False)> _
Public Class SimpleContainerControl
Inherits WebControl
Implements INamingContainer
End Class
[Designer (typeof(SimpleContainerControlDesigner))]
[ParseChildren (false)]
public class SimpleContainerControl : WebControl, INamingContainer
{
}
Save the file.
You have created three custom controls and associated control designers with them. All that remains is to compile the controls into an assembly and then work with them in a visual design tool.
To compile the custom controls and designers
Open a command prompt to the folder where you created the SimpleControlDesigners file. From this prompt, you can compile the source code into an assembly.
Note: |
|---|
To run the .NET Framework compilers from this location, you must have already added the path of your .NET Framework installation to your computer's
PATH variable. Usually, this path is under the Windows installation directory at \Microsoft.NET\Framework\<version number>. If you have not updated the PATH variable, right-click My Computer, select Properties, click the Advanced tab, and click the Environment Variables button. In the System Variables list, double-click the PATH variable. In the Variable value text box, add a semicolon to the end of the existing values in the text box, and then type in the path of your .NET Framework installation. Click OK to close each dialog box.
|
Compile the controls in the SimpleControlDesigners file into an assembly using the following compile command.
csc /r:System.dll /r:System.Design.dll /r:System.Drawing.dll /debug+ /r:System.Web.dll /t:library /out:SimpleControlDesignersCS.dll simplecontroldesigners.cs
vbc /r:System.dll /r:System.Design.dll /r:System.Drawing.dll /debug+ /r:System.Web.dll /t:library /out:SimpleControlDesignersVB.dll SimpleControlDesigners.vb
Move the resulting assembly file to the \Bin folder of the Web site for the page that will host your controls.