When you are creating custom controls, you want to be sure that your controls behave well and don't interfere with the proper behavior of the Visual Studio .NET IDE. Remember, it is your code running in the Form Designer when users are using your custom controls.
If you have public properties that raise an exception, for instance, when invalid data is assigned, you may want to prevent consumers from modifying a property of a control at design time. A couple of attributes control the accessibility of a property in the Properties window. The EditorBrowsableAttribute determines whether a property or method is visible in a designer. For example, Intellisense uses the EditorBrowsableAttribute to determine which members show up in the Intellisense list. The DesignerSerializationVisibilityAttribute is used to determine how a property is serialized by a designer. For example, if a required property throws an exception on an invalid value, then when the designer deserializes that null property the designer would fail on the exception. An exception at design time would prevent the IDE from opening your user control. The BrowsableAttribute is used to control whether a property shows up in the Properties window at design time. Combining these three properties can help you manage how your custom control behaves in the IDE at design time.
Applying the EditorBrowsableAttribute
Suppose you elected to inhibit general access to the identity column from a typed data set for novice or intermediate programmers but allow advanced programmers to see it. You might choose to do this because an identity column is read-only and automatically generated. You could apply the EditorBrowsableAttribute to the typed properties in the generated, strongly typed data set. Listing 9.8, using an excerpt taken from the AddressList typed data set and applied to the AddressIDColumn property, shows how to apply the EditorBrowsableAttribute to permit only advanced programmers to see an attribute in the IDE using Intellisense.
Listing 9.8 Applying the EditorBrowsableAttribute
<System.ComponentModel.EditorBrowsable( _ ComponentModel.EditorBrowsableState.Advanced)> _ Friend ReadOnly Property AddressIDColumn() As DataColumn Get Return Me.columnAddressID End Get End Property
The attribute does not affect the property's actual availability. If programmers already know that the property exists, they can certainly use it in their code. With the application of the attribute as shown, it just won't normally show up in Intellisense and will be reported as an error in the Task List. Such an application of the attribute might discourage rampant abuse by novices. With the EditorBrowsableState.Advanced enumeration a member will not show up in Intellisense (Figure 9.9) unless the Hide advanced members option is unchecked in the ToolsOptions dialog under the Text Editor, Basic folder (Figure 9.10).
Figure 9.9. By default Intellisense will hide members marked with the EditorBrowsableState.Advanced enumerated value.
Figure 9.10. Advanced users will know to uncheck the Hide advanced members box in the Options dialog in the IDE to make all members visible in Intellisense.
Applying the DesignerSerializationVisibilityAttribute
Visual Studio .NET uses XML to serialize the resource files of things like forms and user controls. An unmanaged error during the serialization or deserialization process will make the IDE burp and likely fail to properly save or load your form or user control. It is certainly permissible to raise an unhandled exception in a control or form if you are going to require a consumer to handle the exception; however, the IDE cannot know about such requirements after the fact. Thus if you elect to implement a behavioral contract ”the consumer must handle an exception ”it is often prudent to prevent that method or property from being invoked during the serialization process.
You can apply the DesignerSerializationVisibilityAttribute with one of three DesignerSerializationVisibility enumerated values: Content , Hidden , or Visible . Content indicates that code will be serialized for the object, Hidden indicates that the member will not be serialized, and Visible causes the designer to serialize the member. By supplying the DesignerSerializationVisibility.Hidden enumerated value to the DesignerSerializationVisibilityAttribute you can prevent a contract property, for example, from blowing up on serialization. Listing 9.9 shows how the DesignerSerializationVisibilityAttribute was used (in conjunction with the BrowsableAttribute , discussed next ) in our generated typed data set to manage XML serialization during saving and restoring by the designer.
Listing 9.9 Applying the DesignerSerializationVisibilityAttribute
<System.ComponentModel.Browsable(false), _ System.ComponentModel.DesignerSerializationVisibility ( _ System.ComponentModel.DesignerSerializationVisibility.Content)> _ Public ReadOnly Property Addresses As AddressesDataTable Get Return Me.tableAddresses End Get End Property
It is important to keep in mind that any code in a property's getter will be run when an object is serialized, and the setter's code will be run when an object is deserialized. It has been my experience that most code exists in setters, and for this reason it is deserialization ”or opening a resource file ”that is likely to cause most problems. The origination of a deserialization error can be difficult to resolve, especially when you are inheriting from user controls, unless you are specifically aware of the DesignerSerializationVisibilityAttribute .
Applying the BrowsableAttribute
The BrowsableAttribute determines whether a property shows up in the Properties window. Often you will discover this attribute employed with the DesignerSerializationVisibilityAttribute . Our sample application uses the BrowsableAttribute in a couple of places, including in the Count property. A consumer can't change the number of rows in a data set, and a reasonable value is unlikely to exist until the data set is populated . For this reason, the XML Designer applies the Browsable(false) attribute to the public and derived property Count , as shown in Listing 9.10.
Listing 9.10 Applying the BrowsableAttribute
<System.ComponentModel.Browsable(false)> _ Public ReadOnly Property Count As Integer Get Return Me.Rows.Count End Get End Property
If you want to prevent a property from showing up in the Properties window, initialize a BrowsableAttribute with the literal False . I have found this attribute especially useful with Web user controls. Working on a big project in Oregon, I defined a base user control for a big Web application. The user control obtained its data from the business object. The data was set to a public property during user navigation. It doesn't make sense to permit this value to be set at design time because the data represents an object derived from a database read. Hence, I applied the DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden) and Browsable(False) attributes to this property to ensure its availability during runtime yet prevent misuse or serialization errors at design time.