|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionProperty extender providers are widely used in the Windows Forms environment where this technology enjoys full support of the .NET Framework and Visual Studio IDE. Conversely ASP.NET developers do not always fully appreciate the benefits of the technique. This article demonstrates how to take advantage of the property extenders in ASP.NET custom control projects and suggests practical solutions to issues with design-time serialization and state management posed by ASP.NET 2.0 and Visual Studio 2005. There is a common case of user interface requirements that calls for controls presented on a Web Form to expose a specific set of custom properties. For instance certain controls could disable themselves based on current user credentials or display some sort of interactive context-sensitive help. Most often web developers tend to realize such use cases by creating libraries of custom controls representing subclasses of original controls however employing a property extender provider could prove to be the more elegant and effective technique under a wide variety of circumstances. Extender providers add new properties to other controls. Components or controls acting as property providers are responsible for the behavior of the provided properties. The world of Windows Forms Visual Studio renders full support to property extenders including built-in CodeDom serialization thus making the implementation simple and straightforward. On the other hand, developers of custom web controls and components exposing extender providers were forced to custom-code their own serialization logic. In most cases this approach worked better with non-visual designable components as opposed to more common visual controls until Visual Studio 2005 eliminated components and CodeDom serialization from the developer’s arsenal altogether. BackgroundCodeProject has published a number of articles on this subject:
In this article, I would like to introduce in broad terms the concept of property extenders to the ASP.NET practitioners and share some ideas on how to address issues with serialization of provided properties specifically when working with ASP.NET 2.0 and Visual Studio 2005. Anatomy of property extenderAn extender provider component can provide properties to other components in a container. In a sense these other components are acting as clients of an extender provider. One well-known example is an IExtenderProvider interface
public bool CanExtend(object extendee)
{
return extendee is TextBox;
}
ProvidePropertyAttributeThis class-level attribute defines the name of the property offered by a property extender to other components. The class marked by the attribute has to provide implementation of the property code in the form of [ProvideProperty("Validation", typeof(TextBox))]
public class ValidatorControl
…
public TextValidator GetValidation(TextBox textBox)
{ …
As you can see property extender concept is fairly straightforward and permits a great degree of flexibility when adding new features to components in your project. We will cover specifics of building property extenders for ASP.NET applications next. Property extenders in ASP.NETTo better illustrate this fairly complex topic all concepts and techniques are going to be discussed in the context of the sample project MutlifieldValidator (source is attached with this article). It has been developed in C# 2.0 with Visual Studio 2005 Beta 2. While coding I restrained from using generics and other new framework features not available in .NET 1.1 and Visual Studio 2003, therefore the project can be easily ported to that environment as well. Multi-field validator overviewMutlifieldValidator solves the proverbial problem of validating text input with the somewhat ambitious aim of establishing a strong relevance to the practical development tasks in this purely theoretical exercise. This choice of problem domain also allows readers to easily compare this solution with the existing ‘out-of-the-box’ ASP.NET validator control in such areas as usability and functional simplicity. The following requirements definitions are assumed to drive our preference in technology to property extenders:
As directly inferred by our requirement the property extender control will have to provide two properties for each text box – Placing a proper type converter attribute on the class level
We are going to hide
As you can see from the diagram above the public bool CanExtend(object extendee)
{
return extendee is TextBox;
}
To actually define a provided property we are using a [ProvideProperty("Validation", typeof(TextBox))]
…
public TextValidator GetValidation(TextBox textBox)
{
return FindValidation(textBox);
}
…
Why it does not workHaving performed all these or similar steps you should have a fully functional property extender control, and you probably would if this was done in a Windows Forms environment. So what is so different with Web Forms? If you test your control on an actual Web Form you will discover that the property values assigned to ‘client’ controls are ‘disappearing’ within the same design session and there is no persisting into the run-time. Clearly the issue is property serialization. In Windows Forms case, the designer is does all the dirty work serializing extended properties into CodeDom within the Solving the issue of serialization for provided propertiesThere are a number of helpful attributes that allow WebControls to serialize and deserialize their collection-based properties. Since our [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
[PersistenceMode(PersistenceMode.InnerProperty)]
This is an example of the resulting HTML: <cc1:ValidatorControlID="multiFieldValidator"
runat="server"IsValid="True"Font-Bold="True"
Font-Size="Small"ForeColor="Red">
<Validators>
<cc1:TextValidatorExpression="^\d{0,10}$"
Target="txtPhone"
ErrorMessage="phone number should include only numerics">
</cc1:TextValidator>
<cc1:TextValidatorExpression="^[a-zA-Z]{0,16}$"
Target="txtLastName"
ErrorMessage="last name should include only alpha characters">
</cc1:TextValidator>
<cc1:TextValidatorExpression="^[a-zA-Z]{0,16}$"
Target="txtFirstName"
ErrorMessage="first name should include only alpha characters">
</cc1:TextValidator>
</Validators>
</cc1:ValidatorControl>
As you can see all the There is another attribute that can make this task a trivial one. It is called [ParseChildren(true, "Validators")]
public class ValidatorControl : Label, IExtenderProvider,
IValidator
{ …
Now that we have the serialization and deserialization covered there is still one small problem. If you change the values of extended properties in design-time you will notice that the Web Form designer is not always updating the HTML tags representing your Correcting design-time behaviorSince there is obvious gap in Web Form designer functionality that prevents internal void NotifyDesigner()
{
if (this.DesignMode)
{
IDesignerHost dh =
this.Site.Container as IDesignerHost;
LabelDesigner designer =
dh.GetDesigner(this) as LabelDesigner;
PropertyDescriptor pd =
TypeDescriptor.GetProperties(this)["Validators"];
ComponentChangedEventArgs ccea =
new ComponentChangedEventArgs(this, pd,
Validators, Validators);
designer.OnComponentChanged(this, ccea);
}
}
What happens here is we are telling the designer to refresh its rendering of the In the exposed properties of [Description("regex expression for validating a textbox")]
public string Expression
{
get
{
return m_Expression;
}
set
{
m_Expression = value;
NotifyDesigner();
}
}
/// notifies hosting control that a property
/// has been changed (check for null for run-time)
private void NotifyDesigner()
{
if (m_Control != null)
{
m_Control.NotifyDesigner();
}
}
This simple technique will make the ConclusionAs this article demonstrated, there is a fairly straightforward way to leverage powerful extender technology in ASP.NET projects. Coding effort involved in setting up a property extender control is very well balanced by the flexibility and cleanness of the final solution. Developer’s attempts to introduce this .NET feature into Web Forms were somewhat discouraged by the changes that ASP.NET 2.0 has brought about but as we have proven there is a way to overcome the difficulties with serialization of extended properties and Visual Studio designer event model. This paper is by no means a final word on the future of property extenders in ASP.NET environment and the sample project does have its limitations but it provides enough of a starting ground and brings in a new perspective to building elements of complex user interface. I am sure there are significant opportunities for design and experimentation that may lead to a better or a simpler model. Happy coding! History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||