dcsimg
December 3, 2016
Hot Topics:

Composite Custom Web Controls in Managed C++

  • January 5, 2005
  • By Stephen Fraser
  • Send Email »
  • More Articles »

The only tricky part of the preceding code is calling the EnsureChildControls() method, which ensures that child controls have been previously created. If you don't add this, the designer shows you a blank custom control.

When you run the preceding code, you will find some design flaws. First, the textbox is always the same size and you can't line up the labels of more than one instance of the SearchControl (without some major fudging). To fix this, add the fourth server control, the Table, to the composite custom Web control (I find that the Table is the best way to handle almost all layout issues with controls):

void SearchControl::CreateChildControls()
{
   System::Web::UI::WebControls::Table *table = new Table();
   TableRow *row    = new TableRow();
   TableCell *cell1 = new TableCell();
   TableCell *cell2 = new TableCell();
   TableCell *cell3 = new TableCell();

   cell1->Controls->Add(label);
   cell2->Controls->Add(textbox);
   cell3->Controls->Add(button);

   row->Cells->Add(cell1);
   row->Cells->Add(cell2);
   row->Cells->Add(cell3);

   table->Rows->Add(row);

   Controls->Add(table);
}

To handle the aligning issue, add two more properties: LabelWidth and LabelAlign. LabelWidth ensures that the label of the control is a specific Unit size, and LabelAlign allows the label to be aligned using the HorizontalAlign enum:

[Bindable(true), Category("Appearance")]
__property void set_LabelWidth(Unit value);
__property Unit get_LabelWidth();

[Bindable(true), Category("Appearance")]
__property void set_LabelAlign(HorizontalAlign value);
__property HorizontalAlign get_LabelAlign();

Now comes the tricky part. To specify the width and alignment of the label, you change the attributes of the table cell in which it is contained and not the label itself. To simplify things, create a private class variable called cellLabel that replaces cell1 in the CreateChildControls() method. Here are the implementations of the properties LabelWidth and LabelAlign:

Unit SearchControl::get_LabelWidth()
{
   this->EnsureChildControls();
   return cellLabel->Width;
}

void SearchControl::set_LabelWidth(Unit value)
{
   this->EnsureChildControls();
   cellLabel->Width = value;
}

HorizontalAlign SearchControl::get_LabelAlign()
{
   this->EnsureChildControls();
   return cellLabel->HorizontalAlign;
}

void SearchControl::set_LabelAlign(HorizontalAlign value)
{
   this->EnsureChildControls();
   cellLabel->HorizontalAlign = value;
}

To handle the resizing of the textbox, I make it fill up 100 percent of the cell in which it is contained. Thus, when the table is resized, so is the textbox. One neat feature of the method I used is that it allows the label to be a fixed size, say 100px. Then, when the control is resized, the textbox grows with the control or you can specify that the label is a percent of the control—say 30 percent. Thus, when you resize the control, both the label and the textbox are readjusted based on the percentage. Here is a revamped CreateChildControls() method:

void SearchControl::CreateChildControls()
{
   System::Web::UI::WebControls::Table *table = new Table();
   TableRow *row    = new TableRow();
   TableCell *cell2 = new TableCell();
   TableCell *cell3 = new TableCell();

   cellLabel->Controls->Add(label);

   textbox->Width =  Unit::Percentage(100);
   cell2->Controls->Add(textbox);

   cell3->Controls->Add(button);

   row->Cells->Add(cellLabel);
   row->Cells->Add(cell2);

   cell3->Width =  Unit::Percentage(1);
   row->Cells->Add(cell3);

   table->Rows->Add(row);
   table->Width =  Unit::Percentage(100);

   Controls->Add(table);
}

Don't forget to create an instance of labelCell in the constructor (as I did) or you may spend a while trying to figure out why the designer gives you a big error box.

Handling events

Now that you have everything set in the appearance, it's time to give the control some actual functionality. The first thing you may want is the ability to handle the clicking of the control's button. You do this by using an event handler, just as you would for a Windows application or Web application. Add the event handler to the Click event:

button->Click += new EventHandler(this, buttonClicked);

Then, create a method to handle the event:

void SearchControl::buttonClicked(Object *sender, EventArgs *e)
{
   OnClick(e);
}

No rocket science here.

Raising events

What happens if you want the users of your control to have access to the click event? To provide for this, you need to create a public __event on which they can provide their own event handlers:

__event EventHandler* Click;

You might also want to provide a protected method of OnClick() so that, if someone were to inherit from SearchControl, they could provide additional functionality to the Click event before (or after) passing control back to the SearchControl composite custom Web control. If you were paying attention, you may have noticed that the buttonClick() event handler actually calls the OnClick() method, which in effect passed control from the button to any event handlers that may be attached to the Click event of the control:

void SearchControl::OnClick(EventArgs *e)
{
   if (Click != 0)
   Click(this, e);
}

Because the Click event is the default (and only) event, it might be a good idea to add a DefaultEvent("Click") property attribute specifying Click as the default event for the control:

[DefaultProperty("Value"), DefaultEvent("Click"),
                           ToolboxData("<{0}:SearchControl
                           runat=server></{0}:SearchControl>")]
public __gc class SearchControl :
   public System::Web::UI::WebControls::WebControl
{
}

Remember, if you change metadata (attributes), you need to delete and re-refer the assembly for the metadata to be recognized. Once you add the property attribute, you simply have to double-click on the SearchControl control in the designer to have an event handler created for you. (The following code assumes that you use the C# Web application created back in the first installment of this series.)

private void SearchControl1_Click(object sender, System.EventArgs e)
{
   WebCustomControl1.Text = SearchControl1.Value;
}

Because the complete code is pretty lengthy, I will not place it here. Instead, simply download it at this link.

Lessons in Composite Custom Web Controls

This installment on custom Web control development in Managed C++ covered some interesting stuff. First, it created a composite custom Web control made up of four server controls. It demonstrated how to use properties to manipulate the control. It then showed how to handle events generated by the control. Finally, it demonstrated how to pass the events on to the Web application that uses the composite custom Web control.

All that is left is the rendered custom Web control, which the fourth and final installment will cover.

About the Author

Stephen Fraser has 15 years of IT experience working for a number of consulting companies. He has worked at large consulting firms such as of EDS and Andersen Consulting (Accenture) as well as in startup e-business and medical companies. His IT experience covers all aspects of application and Web development and management, ranging from initial concept all the way through to deployment.

Stephen is also the author of several books, including Managed C++ and .NET Development, Real World ASP.NET: Building a Content Management System, and the forthcoming Pro C++/CLI and .NET Version 2.0 Development.





Page 2 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Enterprise Development Update

Don't miss an article. Subscribe to our newsletter below.

Sitemap | Contact Us

Thanks for your registration, follow us on our social networks to keep up-to-date
Rocket Fuel