Working with Custom Provider Controls
page 4 of 9
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 36349/ 106

Newsletter Signup Control

The newsletter signup control is the means to add subscribers to a newsletter item in the database.  Below is the class definition for the control.

Listing 1

[
ValidationProperty("EmailAddress"),
DefaultProperty("EmailAddress"),
DefaultEvent("SigningUp")
]
public class NewsletterSignup : WebControl, IPostBackDataHandler, IPostBackEventHandler
{
}

This control inherits from WebControl and also makes use of capturing post back information (through IPostBackDataHandler), as well as raising events from within the control (IPostBackEventHandler), as we will soon see.  Notice the attributes used; EmailAddress is the property that contains the email address used to sign up, which is the default.  It's also the property that is validated by any validation controls, as designated by the ValidationProperty attribute.  Lastly, DefaultEvent is the default event for the control, so when double-clicking the control in the designer, SigningUp is the event handler created.  Below are some of the properties defined:

Listing 2

[DefaultValue("Signup"), Localizable(true)]
public string ButtonText
{
  get
  {
    object o = ViewState["ButtonText"];
    return (o == null) ? "Signup" : o.ToString();
  }
  set
  {
    ViewState["ButtonText"= value;
  }
}
 
[Localizable(true)]
public string Description
{
  get
  {
    object o = ViewState["Description"];
    return (o == null) ? null : o.ToString();
  }
  set
  {
    ViewState["Description"= value;
  }
}
 
public string EmailAddress
{
  get
  {
    object o = ViewState["EmailAddress"];
    return (o == null) ? null : o.ToString();
  }
  set
  {
    ViewState["EmailAddress"= value;
  }
}
 
public string NewsletterName
{
  get
  {
    object o = ViewState["NewsletterName"];
    return (o == null) ? null : o.ToString();
  }
  set
  {
    ViewState["NewsletterName"= value;
  }
}

NewsletterName is the property that links the signup control to a specific newsletter.  At the current moment, because the values are stored in an underlying data source, the value has to be a manual string that must match up to an existing newsletter defined using the provider.  Designer support has not yet been added, which it may be possible through a custom designer.

The properties are stored in ViewState as the storage mechanism.  The attribute I will mention is the Localizable attribute.  By passing the true value, Localizable allows the value to be localized.  When creating a page resource file with all of the localization keys, these properties can be included in the resource file, and the final value provided at runtime.

This control has events that the page can subscribe to.  Two of the events are SigningUp and SignedUp, which the equivalent On<Event> methods are shown below:

Listing 3

protected virtual void OnSignedUp(EventArgs e)
{
  if (SignedUp != null)
    SignedUp(this, e);
 
  //Clear the email address after signing up
  this.EmailAddress = null;
}
 
protected virtual void OnSigningUp(CancelEventArgs e)
{
  if (SigningUp != null)
    SigningUp(this, e);
}

The data posted back is collected via the LoadPostData method handler, a part of the IPostBackDataHandler interface.  This interface marks a control for PostBack data handling and through this the email address property is returned.  Note that the unique ID is used; you will see later that the control given for the Email Address control is assigned the UniqueID property.

Listing 4

public bool LoadPostData(string postDataKey,
 System.Collections.Specialized.NameValueCollection postCollection)
{
  this.EmailAddress = postCollection[this.UniqueID];
  return false;
}

The IPostBackEventHandler handles events that are raised within the button controls.  That will come next; however, let's look at what happens when the event is raised:

Listing 5

public void RaisePostBackEvent(string eventArgument)
{
  if (SigningUp == null && string.IsNullOrEmpty(this.NewsletterName))
    throw new Exception("The SigningUp event must be handled.");
 
  CancelEventArgs args = new CancelEventArgs(false);
  this.OnSigningUp(args);
 
  if (!args.Cancel)
  {
    if (string.IsNullOrEmpty(this.NewsletterName))
      throw new NullReferenceException("The newsletter is null");
    if (!Newsletter.NewsletterExists(this.NewsletterName))
      throw new Exception("The newsletter provided does not exist");
 
    Newsletter.AddSubscription(this.EmailAddress, this.NewsletterName);
    this.OnSignedUp(EventArgs.Empty);
  }
}

Normally, multiple events can be handled within this event handler, noted by the event argument value.  However, only one event is raised and that is all that needs to be accounted for.  When the event is raised, the newsletter name must be provided through the NewsletterName property, or if the property isn't assigned the SigningUp event must be handled.  For this to work, during the SigningUp event, the NewsletterName must be provided.  If not provided by the end, then an error is raised because the control doesn't know for which newsletter to add the subscriber.  The subscription is added and the SignedUp event is raised.  Below is the rendering process of the control:

Listing 6

protected override void Render(HtmlTextWriter writer)
{
  base.AddAttributesToRender(writer);
  writer.RenderBeginTag(HtmlTextWriterTag.Span);
  writer.AddAttribute(HtmlTextWriterAttribute.Id, this.ClientID);
  writer.AddAttribute(HtmlTextWriterAttribute.Name, this.UniqueID);
  writer.AddAttribute(HtmlTextWriterAttribute.Type, "text");
  writer.AddAttribute(HtmlTextWriterAttribute.Value, this.EmailAddress);
  writer.RenderBeginTag(HtmlTextWriterTag.Input);
  writer.RenderEndTag(); //input
 
  writer.Write("&nbsp;&nbsp;");
 
  writer.AddAttribute(HtmlTextWriterAttribute.Id, this.UniqueID + "signup");
  writer.AddAttribute(HtmlTextWriterAttribute.Href,
    Page.ClientScript.GetPostBackClientHyperlink(this"signup"true));
  writer.RenderBeginTag(HtmlTextWriterTag.A);
  writer.Write(this.ButtonText);
  writer.RenderEndTag(); //a
 
  //If the description exists, render it below the textbox.
  if (!string.IsNullOrEmpty(this.Description))
  {
    writer.Write("<br>");
    writer.Write(this.Description);
  }
 
  writer.RenderEndTag(); //span
}

I noted the process for using the HtmlTextWriter above; notice that in the Render method, the process for creating the interface is rendered.  This is one of the processes to create an interface for a custom control.  Notice that the UniqueID property, assigned to the name HTML attribute above, is used in the LoadPostData method.  Since the UniqueID property is assigned to the textbox, instead of for the link rendered below it, it can be used to retrieve the ViewState information.  The button doesn't matter as much, except for the value provided to the href attribute.  Page.ClientScript.GetPostBackClientHyperlink returns a script with the event argument "signup", which is passed the RaisePostBackEvent method.


View Entire Article

User Comments

No comments posted yet.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2021 ASPAlliance.com  |  Page Processed at 2021-12-04 9:43:11 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search