I haven’t blogged in a while. Some of you may have noticed. Some of you may have rejoiced. I have just started a new job this month after leaving my previous job of almost eight years. I have also been trying to find and purchase a new home for my fiancée and myself. My new job is great but my work with Visual Studio 2005 is exposing me to the many interesting glitches in the .NET framework again.
This week’s gem was encountered while developing a base form to inherit from as a template in several other projects. This base form has a ToolStrip with a collection of standard buttons that will be common to all projects. In VS2005, the ToolStrip and other collection based controls have very limited design-time support in visual inheritance situations. The reasons for this and the associated problems deserve an article of their own that I may write about later.
To workaround this I created a series of properties on the base form to allow some of the standard buttons to be hidden using a simple Boolean property accessible through the designer. Initially I coded these properties to simply map to the ToolStripItem.Visible property on each corresponding button. As all the buttons are visible in the base form, these properties are also naturally true. Unless otherwise specified, the designer will assume that Boolean properties default to false and will only serialize the value of the property to the derived form’s designer code if the value varies from the default. This means that whenever the property is changed to False on the derived form, it doesn’t get serialized and it reverts back to True.
To fix this I tried applying the DefaultValueAttribute to each of the appropriate properties in the base form but the designer still insisted on assuming False was the default. I tried the usual: rebuild the solution, restart Visual Studio, search Google Groups and anything else but nothing helped. I found an older project where I had needed to achieve the same default on a Boolean property and investigated that code. It used the DefaultValueAttribute in the same way but this older project actually worked. I spent quite a while trying to track down the differences and eventually managed to simplify the problem.
Basically if the getter of a Boolean property maps to a private member, a function call, a property on any object or whatever and you use the DefaultValueAttribute to set the default to True it works. If the getter maps to a ToolStripItem.Visible property directly or via nested function calls then the DefaultValueAttribute is ignored. ToolStripItem’s also have an Available property which is effectively equal to Visible with some minor conditions and actually calls the Visible property in it’s implementation, however mapping a Boolean property to ToolStripItem.Available works with the DefaultValueAttribute. As far as I can tell, the only potentially relevant difference between the ToolStripItem.Visible and Available properties is that Visible has the LocalizableAttribute set to true.
According to the documentation the LocalizableAttribute determines whether the designer will serialize the value to code or to a resource file. Considering I simply call the property getter and not inherit from it this should not be a problem but it is the only thing that seems to explain my results. I have built a very simply project to reproduce this strange behaviour and you can
download it here. I don’t know whether this is a bug or is by design but it sure is irritating and I’m concerned that it may appear in other situations. I’d be interested if anyone can shed any more light on this issue.