具有多个零值问题的标志枚举(TextFormatFlags)

发布于 2024-08-14 06:31:04 字数 1585 浏览 5 评论 0原文

在尝试编写自定义控件时,我遇到了 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;

    公共 TextFormatFlags TFFProperty { 获取 { 返回 this.tff; } 设置 { this.tff = 值; } 向新类添加

  • 编译代码

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

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

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

赴月观长安 2024-08-21 06:31:04

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

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

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

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

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

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

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

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

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

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 a TextFormatFlags to the property grid

Edit: The comma-separated list behaviour of Enum.ToString is in fact documented

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文