Wrox Home  
Search
Professional ASP.NET 2.0 Server Control and Component Development
by Shahram Khosravi
August 2006, Paperback


Rendering the Title Bar

So far, you've learned how the RenderWebPart method renders the <table> HTML element and its associated HTML attributes. As mentioned, this table contains two rows where each row contains a single cell. RenderWebPart renders the title bar within the first row and the body of the WebPart control within the second row. Listing 3 presents the code that renders the title bar.

Listing 3: The code that renders the title bar
private void RenderTitleBar(HtmlTextWriter writer, WebPart webPart)
{
  writer.RenderBeginTag(HtmlTextWriterTag.Table);
  writer.RenderBeginTag(HtmlTextWriterTag.Tr);
  writer.RenderBeginTag(HtmlTextWriterTag.Td);
  writer.AddAttribute(HtmlTextWriterAttribute.Src, 
                      ResolveClientUrl(webPart.TitleIconImageUrl));
  writer.RenderBeginTag(HtmlTextWriterTag.Img);
  writer.RenderEndTag();
  
  this.Zone.PartTitleStyle.AddAttributesToRender(writer);
  writer.AddAttribute(HtmlTextWriterAttribute.Id,  
                                 GetWebPartTitleClientID(webPart));
  writer.RenderBeginTag(HtmlTextWriterTag.Td);
  writer.WriteEncodedText(webPart.DisplayTitle + " - " + webPart.Subtitle);
  writer.RenderEndTag();
  writer.RenderBeginTag(HtmlTextWriterTag.Td);
  WebPartVerbCollection verbs = GetWebPartVerbs(webPart);
  verbs = FilterWebPartVerbs(verbs, webPart);
  RenderVerbs(writer);
  writer.RenderEndTag();
  writer.RenderEndTag();
  writer.RenderEndTag();
}

As Listing 3 illustrates, the RenderTitleBar method renders a table with a single row that contains three cells. The method first renders the title icon within the first cell:

writer.RenderBeginTag(HtmlTextWriterTag.Td);
writer.AddAttribute(HtmlTextWriterAttribute.Src, 
                    ResolveClientUrl(webPart.TitleIconImageUrl));
writer.RenderBeginTag(HtmlTextWriterTag.Img);
writer.RenderEndTag();

The method then renders the title text within the second cell:

  Zone.PartTitleStyle.AddAttributesToRender(writer);
  writer.AddAttribute(HtmlTextWriterAttribute.Id,  
 	GetWebPartTitleClientID(webPart));
  writer.RenderBeginTag(HtmlTextWriterTag.Td);
  writer.WriteEncodedText(webPart.DisplayTitle + " - " + webPart.Subtitle);
  writer.RenderEndTag();

Notice that the method calls the GetWebPartTitleClientID method of the WebPartChrome to return the client ID of the cell that contains the title text. This means you can call the GetWebPartTitleClientID method to access the client ID of this cell and use it in your client-side code to add support for the desired DHTML capabilities. You'll see an example of this later in this article.

Finally, the method renders the verbs menu within the third cell:

  writer.RenderBeginTag(HtmlTextWriterTag.Td);
  WebPartVerbCollection verbs = GetWebPartVerbs(webPart);
  verbs = FilterWebPartVerbs(verbs, webPart);
  RenderVerbsMenu(writer, verbs);
  writer.RenderEndTag();

To render the verbs menu, the RenderTitleBar method calls the GetWebPartVerbs method of the WebPartChrome to return the verbs for the specified WebPart control. You can override this method in your custom WebPartChrome to filter the verbs that you don't want the current user to see.

Then it calls the FilterWebPartVerbs method of the WebPartChrome to filter the unwanted verbs. It may seem that FilterWebPartVerbs does exactly what GetWebPartVerbs does. Why have two different methods doing the same thing? The answer lies in the fact that there are two types of filtering. Sometimes you filter verbs based on some application-specific logic. For example, as you'll see later, you can filter verbs based on the role the current user is in. To accomplish this kind of filtering you should override the FilterWebPartVerbs method. There are times when you know in advance what verbs shouldn't be rendered. For example, you may decide your users shouldn't be able to close the WebPart controls in your application. To accomplish this kind of filtering you should override the GetWebPartVerbs method.

So far you've learned how the RenderWebPart method renders the title bar within the first row. Now you'll see how this method renders the body of the WebPart control within the second row. As shown in Listing 2, the method delegates the responsibility of rendering the body or content of the WebPart to the RenderPartContents method. Listing 4 presents the code for this method.

Listing 4: The RenderPartContents method
protected virtual void RenderPartContents(
	HtmlTextWriter writer, WebPart webPart)
{
  if (!string.IsNullOrEmpty(webPart.ConnectErrorMessage))
  {
    if (!this.Zone.ErrorStyle.IsEmpty)
      this.Zone.ErrorStyle.AddAttributesToRender(writer, this.Zone);
    
    writer.RenderBeginTag(HtmlTextWriterTag.Div);
    writer.WriteEncodedText(webPart.ConnectErrorMessage);
    writer.RenderEndTag();
  }
  else
    webPart.RenderControl(writer);
}

RenderPartContents first ensures that there're no connection error messages and then calls the RenderControl method of the WebPart control. Chapter 33 "WebPartManager, Web Parts Connections, and Data-Bound WebPart Controls" of the book Professional ASP.NET 2.0 Server Control and Component Development (Wrox, August 2006, ISBN: 0-471-79350-7) covers Web Parts connections in detail. You can override RenderPartContents in your custom WebPartChrome to take control over how the WebPart content is rendered.

PerformPreRender

As shown in Listing 1, the WebPartChrome class doesn't directly or indirectly derive from the Control base class, which means that WebPartChrome isn't a server control. Recall that every server control exposes methods such as OnPreRender, OnLoad, and others that are automatically called when the page enters the associated phases of its life cycle. Because WebPartChrome isn't a server control, none of its methods or properties is automatically called. WebPartChrome relies on its associated WebPartZoneBase, which is a server control, to call its methods when the page enters the associated phases of its life cycle.

The prerender phase plays a significant role when it comes to adding support for DHTML capabilities because the client-side scripts must be registered for rendering in this phase. You can't add these scripts to the RenderWebPart method because this method is called in the rendering phase, not the prerendering phase.

To address this problem, WebPartChrome exposes a method named PerformPreRender. However, because WebPartChrome isn't a server control, its PerformPreRender method will not be automatically called when the page enters its prerender phase. That's why the OnPreRender method of the associated WebPartZoneBase calls the PerformPreRender method of the WebPartChrome as shown in Listing 5.

Listing 5: The OnPreRender method of the WebPartZoneBase control
protected internal override void OnPreRender(EventArgs e)
{
  base.OnPreRender(e);
  WebPartVerbsEventArgs args = new WebPartVerbsEventArgs();
  OnCreateVerbs(args);
  verbs = args1.Verbs;
	WebPartChrome.PerformPreRender();
}

Besides the methods discussed so far, the WebPartChrome also exposes two properties named Zone and WebPartManager, which respectively refer to the WebPartZoneBase and WebPartManager associated with the WebPartChrome object.

The next section builds on what you've learned about WebPartChrome to show you how to develop your own custom WebPartChrome to take control over the rendering of the WebPart controls that the associated zone contains.