Microsoft KB Archive/324301

= HOW TO: Create a Web Control with an Expandable Property in the Designer by Using Visual C# .NET =

Article ID: 324301

Article Last Modified on 6/19/2003

-

APPLIES TO


 * Microsoft ASP.NET 1.0
 * Microsoft Visual C# .NET 2002 Standard Edition
 * Microsoft ASP.NET 1.1
 * Microsoft Visual C# .NET 2003 Standard Edition

-



This article was previously published under Q324301



For a Microsoft Visual Basic .NET version of this article, see 319626.

This article refers to the following Microsoft .NET Framework Class Library namespaces:
 * System.ComponentModel
 * System.Web.UI
 * System.Web.UI.WebControls
 * System.Globalization

IN THIS TASK
SUMMARY
 * Implement the Custom Control with ExpandableObjectConverter
 * Test the Custom Control with ExpandableObjectConverter
 * Implement the Custom Control with Custom TypeConverter
 * Test the Custom Control with Custom TypeConverter

REFERENCES



SUMMARY
This step-by-step article demonstrates how to use Visual C# .NET to create a custom Web control that has an expandable property. Properties can be expanded into subproperties for logical organization. The sample in this article demonstrates how to use a TypeConverter object of the ExpandableObjectConverter class and how to implement a custom TypeConverter object.

With the Microsoft Visual Studio .NET property browser, you can display nested properties. As a result, you can group properties more granularly and logically than categories. Nested properties are also available in both categorized and alphabetical sort mode. This helps to keep property lists compact.

back to the top

Implement the Custom Control with ExpandableObjectConverter
 Follow these steps to create a new Visual C# .NET Web Control Library project that is named ControlSampleLibrary:  Start Microsoft Visual Studio .NET. On the File menu, point to New, and then click Project. In the New Project dialog box, click Visual C# Projects under Project Types, and then click Web Control Library under Templates. In the Name box, type ControlSampleLibrary .  Rename the resulting project file (WebCustomControl1.cs) as EmployeeControl.cs.</li>  Replace the default implementation of the control with the following code: //System.ComponentModel provides the necessary attributes. using System; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel;

namespace ControlSampleLibrary {   ///     /// Summary description for WebCustomControl1. ///    [DefaultProperty(&quot;EmployeeInfo&quot;), ToolboxData(&quot;<{0}:EmployeeControl runat=server></{0}:EmployeeControl>&quot;)] public class EmployeeControl: System.Web.UI.WebControls.WebControl {       private EmployeeInfoClass empInfo = new EmployeeInfoClass; //PersistenceMode.InnerProperty: Specifies that the property persists in       //the ASP.NET server control as a nested tag. //DesignerSerializationVisibility.Content: Specifies that a visual //designer serializes the contents of this property instead of the //property itself. [DefaultValue(&quot;&quot;), Category(&quot;Custom&quot;), PersistenceMode(PersistenceMode.InnerProperty), DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] public EmployeeInfoClass EmployeeInfo {           get{return empInfo;} set{empInfo = value; } }       ///         /// Render this control to the output parameter that is specified. ///        /// <param name=&quot;output&quot;> The HTML writer to write out to         protected override void Render(HtmlTextWriter output) {           string outputString ; outputString = EmployeeInfo.FirstName + &quot; &quot; + EmployeeInfo.LastName + &quot;, &quot; + EmployeeInfo.EmployeeId + &quot; &quot; + &quot; &quot;; output.Write(outputString); }   } }                    </li> On the Project menu, click Add Class. In the Name box, type EmployeeInfoClass.cs .</li>  Replace the default implementation of the EmployeeInfoClass class with the following code: using System.ComponentModel; using System; ///

/// namespace ControlSampleLibrary {   ///     ///ExpandableObjectConverter: Provides a type converter to convert expandable ///objects. It adds support for properties on an object to the methods and ///properties that TypeConverter provides. ///    [TypeConverter(typeof(ExpandableObjectConverter))] public class EmployeeInfoClass {       private string strFirstName ; private string strLastName ; private int iEmpId ; public EmployeeInfoClass {           strFirstName = &quot;&quot;; strLastName = &quot;&quot;; iEmpId = 0; }       [DefaultValue(&quot;&quot;), NotifyParentProperty(true), RefreshProperties(RefreshProperties.Repaint)] public string FirstName {           get {               return strFirstName; }

set {               strFirstName = value; }       }        [DefaultValue(&quot;&quot;), NotifyParentProperty(true), RefreshProperties(RefreshProperties.Repaint)] public string LastName {           get {               return strLastName; }           set {               strLastName = value; }

}             [DefaultValue(&quot;&quot;), NotifyParentProperty(true), RefreshProperties(RefreshProperties.Repaint)] public int EmployeeId {           get {               return iEmpId; }           set {               iEmpId = value; }       }    } }                    </li> On the Build menu, click Build Solution to build the solution. Alternatively, press CTRL+SHIFT+B.</li></ol>

back to the top

Test the Custom Control with ExpandableObjectConverter
 Follow these steps to create a new ASP.NET Web Application project:  Start Visual Studio .NET.</li> On the File menu, point to New, and then click Project.</li> In the New Project dialog box, click Visual C# Projects under Project Types, click ASP.NET Web Application under Templates, and then click OK.</li></ol> </li> Follow these steps to add the EmployeeControl control to the Visual Studio .NET toolbox:  In Design view, right-click the Web Forms tab in the toolbox, and then click Customize Toolbox.</li> Click the .NET Framework Components tab.</li> Click Browse, and then locate the folder that contains the ControlSampleLibrary.dll assembly. Select the file, and then click Open.</li> <li>After the reference to the control is added, click OK.</li></ol> </li> <li>Drag the EmployeeControl control from the toolbox to the WebForm1.aspx page.</li> <li>Click the EmployeeControl control. Notice that the Properties window displays the EmployeeInfo property. If you select the categorized option, the EmployeeInfo property is listed under the &quot;custom&quot; category.</li> <li>Expand the EmployeeInfo property into EmployeeId, FirstName, and LastName for separate entries, and then add some data to these properties.</li> <li>Build the solution, and then open the WebForm1.aspx page in your browser to test that your data is rendered.</li></ol>

back to the top

Implement the Custom Control with Custom TypeConverter
Because the property browser only works with strings directly, the property browser relies on TypeConverter classes to convert those string values to the type that the property expects, and vice versa. TypeConverter classes also control expandability and allow complex types to work seamlessly with the property browser.

In this section, you implement a custom TypeConverter object that inherits from the ExpandableObjectConverter class. This custom TypeConverter converts an EmployeeInfo type to and from a string. <ol> <li>On the Project menu, click Add Class to add a class that is named EmployeeInfoConverter.cs to ControlSampleLibrary.</li> <li> Replace the default implementation of the EmployeeInfoConverter class with the following code: using System; using System.ComponentModel; using System.Globalization;

namespace ControlSampleLibrary {   ///     /// Summary description for EmployeeInfoConverter. ///    public class EmployeeInfoConverter : ExpandableObjectConverter {       ///         /// CanConvertFrom specifies which data types the converter can convert from. ///        /// <param name=&quot;context&quot;> /// <param name=&quot;t&quot;> ///         public override bool CanConvertFrom(ITypeDescriptorContext context, Type t)         { if (t == typeof(string)) {               return true; }           return base.CanConvertFrom(context, t); }       ///         ///ConvertFrom actually implements the conversion. ///        /// <param name=&quot;context&quot;> /// <param name=&quot;info&quot;> /// <param name=&quot;value&quot;> ///         public override object ConvertFrom(            ITypeDescriptorContext context,             CultureInfo info,            object value) {           if (value is string) {               try {                   string s = (string) value; //Parse the format &quot;FirstName LastName, (EmployeeId)&quot; int space = s.IndexOf(' '); if (space != -1) {                       //Now that you have the space, get // the FirstName. string firstname = s.Substring(0, space); int paren = s.LastIndexOf('(');                       if (paren != -1 && s.LastIndexOf(')') == s.Length - 1) {                           //Pick up the State. string lastname = s.Substring(space + 1, paren - space - 1); //Get the Zip. int employeeid = Int32.Parse(s.Substring(paren + 1, s.Length - paren - 3)); EmployeeInfoClass e = new EmployeeInfoClass; e.EmployeeId = employeeid; e.FirstName = firstname.Trim; e.LastName = lastname.Trim; return e;                       } }               }                catch{} // If you got this far, complain that you // could not parse the string. throw new ArgumentException(&quot;Cannot convert '&quot; + (string)value + &quot;' to type HomeAddress&quot;); }           return base.ConvertFrom(context, info, value); }       ///         ///CanConvertTo specifies which data types the converter can convert to. ///        /// <param name=&quot;context&quot;> /// <param name=&quot;culture&quot;> /// <param name=&quot;value&quot;> /// <param name=&quot;destType&quot;> ///         public override object ConvertTo(            ITypeDescriptorContext context,             CultureInfo culture,             object value,                Type destType) {           if (destType == typeof(string)) {               EmployeeInfoClass  e = (EmployeeInfoClass)value; //Build the string as &quot;Street, State, (Zip)&quot; string result; result = e.FirstName + &quot; &quot; + e.LastName + &quot;, (&quot; + e.EmployeeId.ToString + &quot;)&quot;; return result; }           return base.ConvertTo(context, culture, value, destType); }

} }                   </li> <li> In the EmployeeInfoClass.cs module, change the following line [TypeConverter(typeof(ExpandableObjectConverter))] to: [TypeConverter(typeof(EmployeeInfoConverter))] </li> <li>On the Build menu, click Build Solution to build the solution. Alternatively, press CTRL+SHIFT+B.</li></ol>

back to the top

Test the Custom Control with Custom TypeConverter
To test the new implementation, follow the same steps in the &quot;Test the Custom Control with ExpandableObjectConverter&quot; section of this article. Notice that the EmployeeInfo property is expandable and allows the user to handle this type either as subproperties or as a single string.

back to the top

<div class="references_section">