Categories
NETCF

Control and Component Designers Part Two – Hanging the Decorations

How the designer interprets your components is from a mixture of reflection to actually see what properties you expose, but also attributes which allow you to override this behaviour.


The first attributes which are required for any component to appear in the toolbox are:-


#if DESIGN

[ToolboxItemFilter(“NETCF”,ToolboxItemFilterType.Require),

ToolboxItemFilter(“System.CF.Windows.Forms”, ToolboxItemFilterType.Custom)]

#endif



This ensures that the component only appears on the device controls toolbar and not within a desktop project. We wrap this in an if DESIGN block so that the attribute is not added to the runtime control (because the CF assemblies don’t include this attribute). The ToolboxItemFilterAttribute can be found in the System.ComponentModel namespace.


If you build the libraries now you should be able to add these components to your toolbox. Open a new device project and open a form in the designer, right click the toolbox and select “Add/Remove Items…” then browse to the output of your project e.g. binDesigner once you have added the file and closed the dialog you should have some new entries in your toolbox:-


In order for the properties pane to work correctly we need to do some further decorating. For most properties you’ll be dealing with fundamental types which visual studio can display automatically. It is a good practise to specify the default values for these fields, in this way if you set the properties to the default it won’t generate code to assign to the property, also the property pane displays non-default values in bold so you can quickly see which have been set to a specific value. The DefaultValueAttribute accepts an object, for example in the case of the ProcessStartInfo the FileName default is an empty string


#if DESIGN
        [DefaultValue(“”), RecommendedAsConfigurable(true)]
#endif
        public string FileName


Some properties will have no meaning at design time such as the Handle property of the Process, using the BrowsableAttribute with a value of false will hide the property


#if DESIGN

[Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]

#endif

public IntPtr Handle


The DesignerSerializationVisibility attribute ensures that this property is excluded from the data serialized to describe your component.


If you have a property which is of type Object then the designer will have no idea what is valid to assign to this and it will appear greyed out. Some of our components and controls now include a Tag property which allows you to tag an object of any type which may contain supporting data. On the desktop this is exposed as a string, so we do the same in our designer support. At runtime you can still assign any object to this property. We also apply the BindableAttribute which tells the designer that this property may be used in data binding.


#if DESIGN

[Bindable(true), DefaultValue((string) null), TypeConverter(typeof(StringConverter))]

#endif

public object Tag

 


Some properties will use other classes which themselves contain multiple properties. A good example is the ProcessStartInfo which is used with the Process class. In order to allow the designer to display this correctly as a nested object we apply the TypeConverterAttribute and give it a value of ExpandableObjectConverter, this allows the designer to populate the property pane with the various properties contained within it.


#if DESIGN

[TypeConverter(typeof(ExpandableObjectConverter))]

#endif

public sealed class ProcessStartInfo


We apply the same selection of properties to define the default values for the properties within this class. Now the property pane takes on a logical nested appearance and we can setup all of these properties at design time:-


To ensure these properties are written out in our code by the designer we need to add the DesignerSerializationVisibilityAttribute:-


#if DESIGN

[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]

#endif

public ProcessStartInfo StartInfo


Optionally you can specify categories and descriptions for properties and events. Depending on the user’s preferences the property pane may be shown by category or alphabetically. By default properties are added to the “Misc” category. The grey box below the actual property list will show a short description as defined by the DescriptionAttribute as used here in the BackgroundWorker class.


#if DESIGN

[Category(“Asynchronous”),

Description(“Event handler to run on a different thread when the operation begins.”)]

#endif

public event DoWorkEventHandler DoWork;


Part 1 | Part 2 | Part 3 | Part 4

By Peter Foot

Microsoft Windows Development MVP