Flags enumeration with multiple zero values problem (TextFormatFlags)
While trying to write a custom control I've come across a problem with the System.Windows.Forms.TextFormatFlags enum in combination with the Visual Studio (2005/2008) editor. The reason for this problem seems to come from the fact that this enum has multiple members which map to a zero value. Selecting any of these members (GlyphOverhangPadding, Left, Default, Top) results in the editor setting the property to
this.customControl.TextFormatFlags = System.Windows.Forms.TextFormatFlags.GlyphOverhangPadding;
The code compiles, as expected. However, selecting any non-zero member (e.g. "Right") from the editor's property grid results in the following:
this.customControl.TextFormatFlags = System.Windows.Forms.TextFormatFlags.Left, Default, Top, Right;
Obviously this does not compile. Selecting more than one non-zero member (Through a UITypeEditor, e.g. "Right | Bottom") results in the following:
this.customControl.TextFormatFlags = ((System.Windows.Forms.TextFormatFlags)((System.Windows.Forms.TextFormatFlags.Left, Default, Top, Right | System.Windows.Forms.TextFormatFlags.Left, Default, Top, Bottom)));
As you can see, the editor adds three of the four zero-value members to any selected item.
If you wish to reproduce this issue:
- Create a new project in Visual Studio 2005/2008 (Windows Forms Application)
- Add a Custom Control to the project.
Add a private field and public property to the new class:
private TextFormatFlags tff = TextFormatFlags.Default;
public TextFormatFlags TFFProperty { get { return this.tff; } set { this.tff = value; } }
Compile the code
- Open Form1 in the designer and add CustomControl1 to it
- The code compiles fine
- Now open the properties of CustomControl1 in the editor's PropertyGrid
- You should see the TFFProperty under the "Misc" section
- The property offers several values, most of which contain a comma.
- Selecting any of the values with a comma (e.g. "Left, Default, Top, HorizontalCenter) results in non compilable code
The same happens if you create your own enum with the Flags attribute and add more than one member mapped to zero (which is a kind of malformed flags enum?). I've verified that this is not a bug with the UITypeEditor I'm using (The same problem occurs without using the UITypeEditor). I've tried to circumvent the problem with a Converter, so far without success. If anyone has any ideas on how to solve this problem开发者_如何学编程 I'd be glad to hear them.
I checked through the various classes in the System.ComponentModel.Design.Serialization
namespace using Reflector, and I think the CodeDom serializer is being a bit naughty.
Enums get handled by EnumCodeDomSerializer.Serialize
, whose purpose is to take an enum and turn it into a System.CodeDom.CodeExpression
object that represents what you see in the designer file.
This method correctly uses CodeBinaryOperatorExpression
to handle the |
aspect of the expression. However, for the individual enum values, it uses Enum.ToString
via EnumTypeConverter
and sticks the resulting string directly into the expression tree.
I think Enum.ToString
is the ultimate cause of what you're seeing:
If multiple enumeration members have the same underlying value and you attempt to retrieve the string representation of an enumeration member's name based on its underlying value, your code should not make any assumptions about which name the method will return.
Admittedly the MSDN page on Enum.ToString
doesn't talk about the commas, but it still doesn't seem safe to rely on the output of Enum.ToString
being a valid C# expression.
I'm not sure what this means for your control:
- Clearly you can define your own replacement for
TextFormatFlags
and do it without the duplicated zero flags - You may be able to hack it with a custom type converter, maybe one that converts to
InstanceDescriptor
. This gives you a little more control over what appears in the designer-generated code. - You could possibly expose an
int
to the designer serializer but aTextFormatFlags
to the property grid
Edit: The comma-separated list behaviour of Enum.ToString
is in fact documented
精彩评论