How to create an expandable property (struct) on a custom controlhttp://forums.asp.net/t/1778284.aspx/1?How+to+create+an+expandable+property+struct+on+a+custom+controlThu, 27 Sep 2012 20:19:13 -040017782844870704http://forums.asp.net/p/1778284/4870704.aspx/1?How+to+create+an+expandable+property+struct+on+a+custom+controlHow to create an expandable property (struct) on a custom control <p>Hi All</p> <p>I have a piece of code that is giving me around my head. These are the facts:</p> <ol> <li>I have User control that has a Struct property and I would like that this property will be visible in the Property Window of the Visual Studio Designer. </li><li>So far, I have achived that the Struct appears but it is not showing its propertoies. I mean, the plus sign (&#43;) is not visible. </li><li>I'm using VS 2005. I tested in VS 2010. However the behaivor is the same. </li><li>These are the urls that I'm following: A Struct TypeConvertr (<a href="http://www.morganskinner.com/Articles/AStructTypeConverter/">http://www.morganskinner.com/Articles/AStructTypeConverter/</a>), Custom User control property (<a href="http://stackoverflow.com/questions/7539094/usercontrol-custom-property-grayed">http://stackoverflow.com/questions/7539094/usercontrol-custom-property-grayed</a>), NotifyParentProperty Attribute (<a href="http://msdn.microsoft.com/en-us/library/system.componentmodel.notifyparentpropertyattribute.aspx">http://msdn.microsoft.com/en-us/library/system.componentmodel.notifyparentpropertyattribute.aspx</a>) </li><li>My code: </li></ol> <p>The declaration of the Struct:</p> <pre class="prettyprint">[TypeConverter(typeof(ColumnDefinitionsConverter))] public struct ColumnDefinitions { public ColumnDefinitions(string A, string B) { _ColName = A; _ColType = B; } [Browsable(true)] [NotifyParentProperty(true)] [EditorBrowsable(EditorBrowsableState.Always)] public string ColName { get { return _ColName; } set { _ColName = value; } } [Browsable(true)] [NotifyParentProperty(true)] [EditorBrowsable(EditorBrowsableState.Always)] public string ColType { get { return _ColType; } set { _ColType = value; } } private string _ColName; private string _ColType; }</pre> <pre class="prettyprint">&nbsp;</pre> <pre class="prettyprint">The code for the ConverterType</pre> <pre class="prettyprint">public class ColumnDefinitionsConverter : TypeConverter { /// &lt;summary&gt; /// Can the framework call CreateInstance? /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override bool GetCreateInstanceSupported(ITypeDescriptorContext context) { // Yes! return true; } /// &lt;summary&gt; /// Satisfy the CreateInstance call by reading data from the propertyValues dictionary /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;param name="propertyValues"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues) { // Get values of "Me" and "You" properties from the dictionary, and // create a new instance which is returned to the caller return new ColumnDefinitions(propertyValues["ColName"] as string, propertyValues["ColType"] as string); } /// &lt;summary&gt; /// Does this struct expose properties? /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override bool GetPropertiesSupported(ITypeDescriptorContext context) { // Yes! return true; } /// &lt;summary&gt; /// Return the properties of this struct /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;param name="value"&gt;&lt;/param&gt; /// &lt;param name="attributes"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override PropertyDescriptorCollection GetProperties(ITypeDescriptorContext context, object value, Attribute[] attributes) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(value, attributes); // Putz around with the property collection if you like - here I'm changing the display order. string[] sortOrder = new string[2]; sortOrder[0] = "ColName"; sortOrder[1] = "ColType"; // Return a sorted list of properties return properties.Sort(sortOrder); } /// &lt;summary&gt; /// Check what this type can be created from /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;param name="sourceType"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override bool CanConvertFrom(ITypeDescriptorContext context, System.Type sourceType) { // Just strings for now bool canConvert = (sourceType == typeof(string)); if (!canConvert) canConvert = base.CanConvertFrom(context, sourceType); return canConvert; } /// &lt;summary&gt; /// Convert from a specified type to a Doofer, if possible /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;param name="culture"&gt;&lt;/param&gt; /// &lt;param name="value"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override object ConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value) { string sValue = value as string; object retVal = null; if (sValue != null) { // Check that the string actually has something in it... sValue = sValue.Trim(); if (sValue.Length != 0) { // Parse the string if (null == culture) culture = CultureInfo.CurrentCulture; // Split the string based on the cultures list separator string[] parms = sValue.Split(new char[] { culture.TextInfo.ListSeparator[0] }); if (parms.Length == 2) { // Should have an integer and a string. string colName = parms[0]; string colType = parms[1]; // And finally create the object retVal = new ColumnDefinitions(colName, colType); } } } else retVal = base.ConvertFrom(context, culture, value); return retVal; } /// &lt;summary&gt; /// Check what the type can be converted to /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;param name="destinationType"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override bool CanConvertTo(ITypeDescriptorContext context, System.Type destinationType) { // InstanceDescriptor is used in the code behind bool canConvert = (destinationType == typeof(InstanceDescriptor)); if (!canConvert) canConvert = base.CanConvertFrom(context, destinationType); return canConvert; } /// &lt;summary&gt; /// Convert to a specified type /// &lt;/summary&gt; /// &lt;param name="context"&gt;&lt;/param&gt; /// &lt;param name="culture"&gt;&lt;/param&gt; /// &lt;param name="value"&gt;&lt;/param&gt; /// &lt;param name="destinationType"&gt;&lt;/param&gt; /// &lt;returns&gt;&lt;/returns&gt; public override object ConvertTo(System.ComponentModel.ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, System.Type destinationType) { object retVal = null; ColumnDefinitions colDefi = (ColumnDefinitions)value; // If this is an instance descriptor... if (destinationType == typeof(InstanceDescriptor)) { System.Type[] argTypes = new System.Type[2]; argTypes[0] = typeof(string); argTypes[1] = typeof(string); // Lookup the appropriate Doofer constructor ConstructorInfo constructor = typeof(ColumnDefinitions).GetConstructor(argTypes); object[] arguments = new object[2]; arguments[0] = colDefi.ColName; arguments[1] = colDefi.ColType; // And return an instance descriptor to the caller. Will fill in the CodeBehind stuff in VS.Net retVal = new InstanceDescriptor(constructor, arguments); } else if (destinationType == typeof(string)) { // If it's a string, return one to the caller if (null == culture) culture = CultureInfo.CurrentCulture; string[] values = new string[2]; // I'm a bit of a culture vulture - do it properly! TypeConverter numberConverter = TypeDescriptor.GetConverter(typeof(int)); //values[0] = numberConverter.ConvertToString(context, culture, doofer.Me); values[0] = colDefi.ColName; values[1] = colDefi.ColType; // A useful method - join an array of strings using a separator, in this instance the culture specific one retVal = String.Join(culture.TextInfo.ListSeparator + " ", values); } else retVal = base.ConvertTo(context, culture, value, destinationType); return retVal; } }</pre> <pre class="prettyprint">Now, the code inside the User control class </pre> <pre class="prettyprint">public partial class ucLoadFileInBatch : System.Web.UI.UserControl { ColumnDefinitions _objColDef = new ColumnDefinitions(); public ColumnDefinitions ColDef { get { return _objColDef; } set { _objColDef = value; } } . . . . . . </pre> <p>As mentioned the ColDef method appears on the Property Window from VS, but &#43; sign to expand the Struct and be able to see its ColName and ColType properties is not displayed.<br> Does anyone how to achieved this? or<br> What's wrong in the code? or<br> Does anyone has a step by step example of this?<br> I will really appreacite your help on this. As mentioned, it has giving me around my head for a few days :-S</p> <p>Regards!!</p> 2012-03-08T23:44:20-05:004873399http://forums.asp.net/p/1778284/4873399.aspx/1?Re+How+to+create+an+expandable+property+struct+on+a+custom+controlRe: How to create an expandable property (struct) on a custom control <p>Hi All again</p> <p>Just for the record. In the 3th links mentioned I tested it in both Winforms and asp.net. For the Winforms it works OK (the properties of my custum control are expandable in Design mode), however for an Asp.Net page it also worked but without displaying the plus sign (&#43;) on the properties that shlod be expandable. It jus show the property no the &#43; sign.</p> <p>so, based on this test is there an special way to do this for Asp.Net? I mean, set a property as expandable. I'm tested it in Asp.Net 2.0 and Asp.Net 3.5 and in both cases I got the same result</p> <p>Or, Which VS framework this should in?</p> <p>Thanks</p> 2012-03-10T23:08:59-05:004873432http://forums.asp.net/p/1778284/4873432.aspx/1?Re+How+to+create+an+expandable+property+struct+on+a+custom+controlRe: How to create an expandable property (struct) on a custom control <p>Maybe that's the problem of ITypeConvertorplz check that:-)</p> 2012-03-11T00:39:19-05:005161563http://forums.asp.net/p/1778284/5161563.aspx/1?Re+How+to+create+an+expandable+property+struct+on+a+custom+controlRe: How to create an expandable property (struct) on a custom control <p>I may not be interpreting this correctly, but I like to use Enum.</p> <p>That way, you have a property in your designer with a dropdown list. It is very easy to make and very easy to use.</p> <p>http://msdn.microsoft.com/en-us/library/sbbt4032%28v=vs.80%29.aspx</p> <p>pubic property myCustomProperty as predefinedEnumListName</p> 2012-09-27T20:19:13-04:00