Wrox Programmer Forums
|
BOOK: Professional ASP.NET 2.0 Server Control and Component Development ISBN: 978-0-471-79350-2
This is the forum to discuss the Wrox book Professional ASP.NET 2.0 Server Control and Component Development by Dr. Shahram Khosravi; ISBN: 9780471793502
Welcome to the p2p.wrox.com Forums.

You are currently viewing the BOOK: Professional ASP.NET 2.0 Server Control and Component Development ISBN: 978-0-471-79350-2 section of the Wrox Programmer to Programmer discussions. This is a community of software programmers and website developers including Wrox book authors and readers. New member registration was closed in 2019. New posts were shut off and the site was archived into this static format as of October 1, 2020. If you require technical support for a Wrox book please contact http://hub.wiley.com
 
Old October 30th, 2006, 03:56 PM
Registered User
 
Join Date: Oct 2006
Posts: 1
Thanks: 0
Thanked 0 Times in 0 Posts
Default Composite Control Property Exposure Invalid...

Dr. Khosravi -
I've been attempting to build a simple composite control utilizing a checkbox, label, textbox, and button child controls but have run into some perplexing problems which manifest themselves even when using your own sample code verbatim. Here's the problem:
I'm attempting to expose the Text properties of the child controls via properties on the composite (containing) control (as demonstrated in Ch5, p112), but in the VS designer the changed values of these properties _never_ appear, are reset at runtime, and therefore never used. Upon setting the text value(s) of these properties, the appropriate attributes _are_ added to the generated html, but are not persisted nor shown in the property designer. While using/debugging your own example, this is also true, and the CreateChildControls() method isn't called once but 3+ times -- it was my understanding that EnsureChildControls() was specifically meant to make sure this _didn't_ happen, and even though ChildControlsCreated is being set to True on each pass, CreateChildControls() is still being called multiple times for a single instance of the control on the page. It looks almost as if the custom composite control might be instantiated multiple times for a single control declaration on the page, which does not make sense.
Additionally, because of the multiple calls to CreateChildControls, the changed property values applied to the underlying controls are being reverted (since Controls.Clear() is called and the child controls re-created from scratch). Again -- please note that this behavior even happens in your very own sample, used verbatim.
Can you explain where the issue is and perhaps provide a fix in the book errata?
Thanks!
A.
 
Old October 31st, 2006, 04:48 AM
Wrox Author
 
Join Date: Aug 2006
Posts: 24
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Hi, alandye,

The ASP.NET 2.0 server control and component development is a huge subject, which makes it impossible for an author to cover everything in one book. I had to leave out some topics to make room for more important topics such as Web Parts, Ajax-enabled controls, etc. As I've noted in Chapter 5, I dropped more detailed discussions of the ICompositeControlDesignerAccessor interface from this chapter. Here is portion of what I originally intended to include in this chapter but dropped it to make room for other topics.

The ICompositeControlDesignerAccessor interface exposes a single method as shown in the following:

namespace System.Web.UI.WebControls
{
  public interface ICompositeControlDesignerAccessor
  {
    void RecreateChildControls();
  }
}

Server controls implement this interface to allow visual designers such as Visual Studio 2005 to recreate their control hierarchy. When you change the property of a server control in the VS Property window, under the hood VS calls the RecreateChildControls method of the control to recreate its child controls.

If you derive your custom control from the CompositeControl base class, you don't have to worry about implementing the ICompositeControlDesignerAccessor interface because the base class has already implemented it. Let's take a look under the hood of the CompositeControl class's implementation of the RecreateChildControls method:

public abstract class CompositeControl : WebControl, INamingContainer, ICompositeControlDesignerAccessor
{
  void ICompositeControlDesignerAccessor.RecreateChildCon trols()
  {
    this.RecreateChildControls();
  }

  protected virtual void RecreateChildControls()
  {
    base.ChildControlsCreated = false;
    this.EnsureChildControls();
  }
}

As you can see, the RecreateChildControls method first sets the ChildControlsCreated property to false and then calls the EnsureChildControls method, which in turn calls the CreateChildControls method.

Recall that the CreateChildControls method of a composite control first calls the Clear() method to remove all the child controls from the Controls collection of the composite control, which means that all the property values of the child controls are lost forever. That is the reason for the design-time misbehavior you mentioned in your posting.

You may be wondering how come this problem only occurs in design-time considering the fact that the same CreateChildControls method is also called in runtime when the end user clicks the Submit button to post the page back to the server. The answer to this question lies in the ASP.NET View State mechanism as I've thoroughly discussed in my book. At the end of each request, this mechanism stores the property values of all child controls in the view state. At the begining of each request, on the other hand, this mechanism retrieves these property values from the view state and assigns them to the properties of the new child controls that the CreateChildControls method creates from scratch. In design-time case, everything is happening locally on your machine and the View State mechanism is not involved. That is why every change you make in the Property window is lost.

There're two approaches to deal with this design-time misbehavior. The first approach is the easiest one. Just modify the properties of the composite control to use private fields as backing store. Here is an example:

private string paymentMethodText;
public virtual string PaymentMethodText
{
  get
  {
    if (DesignMode)
      return paymentMethodText;
    EnsureChildControls(); return paymentMethodLabel.Text;
  }
    set
    {
      if (DesignMode) {
        paymentMethodText = value;
        return;
      }
    EnsureChildControls(); paymentMethodLabel.Text = value; }
}

Every server control inherits a Boolean property named DesignMode from the Control base class. This property specifies whether the server control is used in a visual designer. The getter and setter of the PaymentMethodText property first check whether the server control is being used in a visual designer. If so, they use the paymentMethodText private field as the backing store instead of the Text property of the paymentMethodLabel control.

You cannot use a private field as a backing store in runtime because in a Web application the value of the field is lost at the end of each request. The visual designer, on the other hand, is a desktop application, which means that the value of a private field stays around as long as the object that owns the field is around.

I mentioned there're two approaches to tackling the design-time misbehavior you've observerd. The second approach requires you to take these steps. First, use the view state as the backing store for the properties of your composite control. Here is an example:

public virtual string PaymentMethodText
{
  get
  {
    return ViewState["PaymentMethodText"] != null ?
           (string)ViewState["PaymentMethodText"] : "Payment Method";
  }
  set
  {
    ViewState["PaymentMethodText"] = value;
  }
}

Second, assign the values of the properties of the composite control to the properties of the associated child controls. For example,

protected virtual void CreateContainerChildControls(CreditCardFormContain er container)
{
  switch (container.ContainerType)
  {
    case ContainerType.PaymentMethodLabel:
      paymentMethodLabel = new Label();
      paymentMethodLabel.ID = "PaymentMethodLabel";
      paymentMethodLabel.Text = PaymentMethodText;
      container.Controls.Add(paymentMethodLabel);
      break;
    . . .
   }
}

Third, set the EnableViewState property of the child controls to false. This step is important because if you don't turn off the view state of the child controls the same information (i.e. the property value) will be stored twice in the view state the first by the property of the composite control (recall that this property uses view state as the backing store) and the second time by the child control itself.

protected virtual void CreateContainerChildControls(CreditCardFormContain er container)
{
  switch (container.ContainerType)
  {
    case ContainerType.PaymentMethodLabel:
      paymentMethodLabel = new Label();
      paymentMethodLabel.ID = "PaymentMethodLabel";
      paymentMethodLabel.Text = PaymentMethodText;
      paymentMethodLabel.EnableViewState = false;
      container.Controls.Add(paymentMethodLabel);
      break;
    . . .
   }
}

The above discussions should address the design-time misbehavior you mentioned in your posting.

You also raised a second issue in your posting, that is, multiple calls to the CreateChildControls method. This issue is casued by a code error in Listing 5-9. You need to replace the following five lines of code:

paymentMethodLabel.Text = PaymenMethodText;
creditCardNoLabel.Text = CreditCardNoText;
cardholderNameLabel.Text = CardholderNameText;
expirationDateLabel.Text = ExpirationDateText;
submitButton.Text = SubmitButtonText;

with

paymentMethodLabel.Text = "Payment Method";
creditCardNoLabel.Text = "Credit Card No";
cardholderNameLabel.Text = "Cardholder's Name";
expirationDateLabel.Text = "Expiration Date";
submitButton.Text = "Submit";

This is necessary because the PaymentMethodText, CreditCardNoText, CardholderNameText, ExpirationDateText, and SubmitButtonText properties call the EnsureChildControls method, which in turn could call the CreateChildControls method.

I'll make sure that the above five code line chagnes are added to the book errata. Thank you very much for your inputs.

Cheers!
Shahram


-----------------------
Shahram Khosravi, Ph.D.
Author of Professional ASP.NET 2.0 Server Control and Component Development
 
Old March 23rd, 2007, 02:35 PM
Authorized User
 
Join Date: Sep 2006
Posts: 23
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Wow...the author still hasn't managed to update the Errata for this book....there's nothin' worse than that. Who knows how many countless readers have googled themselves to death trying to resolve this issue thinking they could trust in the author's accuracy and *competence*.

Dr., it's great that you have a Ph.D and all, but I think someone who's been to school that long would certainly be capable of *FULLY* updating the Errata so that readers can save countless hours pouring over search engines for help.

 
Old March 23rd, 2007, 02:43 PM
Authorized User
 
Join Date: Sep 2006
Posts: 23
Thanks: 0
Thanked 0 Times in 0 Posts
Default

Another question, Doc:

You documented the 'fix for Listing 5-9 as hardcoding the text values for the given controls. In doing so, design time changes are ignored because the property values are not updated.

Is this what you intended?






Similar Threads
Thread Thread Starter Forum Replies Last Post
invalid reference to property rashi Access 6 September 28th, 2007 11:39 AM
PLEASE HELP - Composite Control brettk_1 ASP.NET 1.0 and 1.1 Professional 0 August 3rd, 2005 06:22 AM
Composite Control bmains .NET Framework 2.0 0 July 25th, 2005 12:57 PM
Invalid use of property error. Bob Rupp BOOK: Beginning Access 2003 VBA 1 March 4th, 2005 09:09 AM
Invalid use of property hanna VB.NET 2002/2003 Basics 1 March 31st, 2004 06:31 PM





Powered by vBulletin®
Copyright ©2000 - 2020, Jelsoft Enterprises Ltd.
Copyright (c) 2020 John Wiley & Sons, Inc.