2

在尝试编写自定义控件时,我遇到了 System.Windows.Forms.TextFormatFlags 枚举与 Visual Studio (2005/2008) 编辑器结合使用的问题。这个问题的原因似乎来自这个枚举有多个映射到零值的成员。选择这些成员中的任何一个(GlyphOverhangPadding、Left、Default、Top)都会导致编辑器将属性设置为

this.customControl.TextFormatFlags = System.Windows.Forms.TextFormatFlags.GlyphOverhangPadding;

代码按预期编译。但是,从编辑器的属性网格中选择任何非零成员(例如“Right”)会导致以下结果:

this.customControl.TextFormatFlags = System.Windows.Forms.TextFormatFlags.Left, Default, Top, Right;

显然这不会编译。选择多个非零成员(通过 UITypeEditor,例如“Right | Bottom”)会导致以下结果:

this.customControl.TextFormatFlags = ((System.Windows.Forms.TextFormatFlags)((System.Windows.Forms.TextFormatFlags.Left, Default, Top, Right | System.Windows.Forms.TextFormatFlags.Left, Default, Top, Bottom)));

如您所见,编辑器将四个零值成员中的三个添加到任何选定项。

如果您希望重现此问题:

  • 在 Visual Studio 2005/2008(Windows 窗体应用程序)中创建一个新项目
  • 将自定义控件添加到项目中。
  • 将私有字段和公共属性添加到新类:

    私有 TextFormatFlags tff = TextFormatFlags.Default;

    public TextFormatFlags TFFProperty { get { return this.tff; } 设置 { this.tff = 值;} }

  • 编译代码

  • 在设计器中打开 Form1 并将 CustomControl1 添加到其中
  • 代码编译得很好
  • 现在在编辑器的 PropertyGrid 中打开 CustomControl1 的属性
  • 您应该在“杂项”部分下看到 TFFProperty
  • 该属性提供多个值,其中大部分包含逗号。
  • 选择任何带逗号的值(例如“Left、Default、Top、Horizo​​ntalCenter)会导致代码不可编译

如果您使用 Flags 属性创建自己的枚举并添加多个映射到零的成员(这是一种格式错误的标志枚举?),也会发生同样的情况。我已经验证这不是我正在使用的 UITypeEditor 的错误(不使用 UITypeEditor 也会出现同样的问题)。我试图用转换器来规避这个问题,但到目前为止没有成功。如果有人对如何解决这个问题有任何想法,我会很高兴听到他们的声音。

4

1 回答 1

3

我使用 Reflector 检查了命名空间中的各种类System.ComponentModel.Design.Serialization,我认为 CodeDom 序列化程序有点调皮。

枚举由 处理EnumCodeDomSerializer.Serialize,其目的是获取一个枚举并将其转换为一个System.CodeDom.CodeExpression对象,该对象代表您在设计器文件中看到的内容。

此方法正确用于CodeBinaryOperatorExpression处理|表达式的方面。但是,对于单个枚举值,它使用Enum.ToStringviaEnumTypeConverter并将结果字符串直接粘贴到表达式树中。

我认为Enum.ToString这是您所看到的最终原因:

如果多个枚举成员具有相同的基础值,并且您尝试根据其基础值检索枚举成员名称的字符串表示形式,则您的代码不应对该方法将返回哪个名称做出任何假设。

诚然,MSDN 页面上并没有讨论逗号,但依靠输出是有效的 C# 表达式Enum.ToString似乎仍然不安全。Enum.ToString

我不确定这对您的控制意味着什么:

  • 显然,您可以定义自己的替换TextFormatFlags并在没有重复的零标志的情况下执行此操作
  • 您可以使用自定义类型转换器破解它,也许可以转换为InstanceDescriptor. 这使您可以更好地控制设计器生成的代码中出现的内容。
  • 您可以将 a 暴露int给设计器序列化程序,但将 a暴露TextFormatFlags给属性网格

编辑: 逗号分隔的列表行为Enum.ToString实际上已记录在案

于 2009-12-07T20:57:00.027 回答