65.9K
CodeProject 正在变化。 阅读更多。
Home

一个 UITypeEditor,用于轻松编辑属性浏览器中的标志枚举属性

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.92/5 (34投票s)

2006 年 4 月 15 日

3分钟阅读

viewsIcon

131477

downloadIcon

3236

用于在属性浏览器中轻松编辑标志枚举属性的 UITypeEditor。

引言

Visual Studio .NET 的设计时支持非常好,使快速开发窗体和用户控件变得非常容易。即便如此,它也有一些小缺点——有些令人恼火,有些则造成不便。其中一个缺点是在设计时属性浏览器中缺乏一种好的方法来编辑“标志枚举属性”。标志枚举属性是指其类型为应用了FlagsAttribute属性的枚举的属性。此属性指示枚举可以被视为位字段;也就是说,一组标志。此类枚举的一个示例是FontStyle枚举。它包含粗体、斜体和下划线样式的位值,如果需要,可以将它们组合在一起。但是,属性网格没有对这种标志枚举的内置支持——如果要指定字体应该是粗体和斜体,唯一的方法是编写等效的代码。

本文介绍了一个简单的 UITypeEditor,它可以应用于此类标志枚举,并使使用设计时属性浏览器编辑此类属性变得非常容易。

背景

在讨论代码之前,有必要简要介绍一下 UI 类型编辑器是什么。在属性浏览器提供的简单字符串到值和值到字符串转换不够充分或方便的情况下,可以使用 UI 类型编辑器来提供用于编辑属性的高级 UI。例如,所有控件的DockAnchor属性都使用 UI 类型编辑器来轻松编辑属性。要指定属性应使用 UI 类型编辑器,则将EditorAttribute应用于属性的类型或属性本身。在第一种情况下,每当属性具有应用了该属性的类型时,就会使用 UI 类型编辑器。在第二种情况下,仅对该属性使用 UI 类型编辑器。

FlagEnumUIEditor 类

用于标志枚举的 UI 类型编辑器称为FlagEnumUIEditor,它派生自UITypeEditor。它是一个下拉样式编辑器,这意味着当选择属性时,属性浏览器中会显示一个小下拉按钮。单击此按钮时,将显示一个控件,可用于编辑属性。FlagEnumUIEditor使用派生自CheckedListBox的类来显示标志枚举。

FlagCheckedListBox 类

FlagCheckedListBox类派生自CheckedListBox,并包含FlagCheckedListBoxItem类型的项目。每个项目都具有一个值和一个描述,用于对应于枚举成员的值和名称。EnumValue属性用于将枚举值与FlagCheckedListBox关联。

public Enum EnumValue
{
    get
    {
        object e = Enum.ToObject(enumType,GetCurrentValue());
        return (Enum)e;
    }
    set
    {
        
        Items.Clear();
        enumValue = value; // Store the current enum value
        enumType = value.GetType(); // Store enum type
        FillEnumMembers(); // Add items for enum members
        ApplyEnumValue(); // Check/uncheck items depending on enum value
     }
}

FillEnumMembersApplyEnumValue函数如下所示

// Adds items to the checklistbox based on the members of the enum
private void FillEnumMembers()
{
    foreach ( string name in Enum.GetNames(enumType))
    {
        object val = Enum.Parse(enumType,name);
        int intVal = (int)Convert.ChangeType(val, typeof(int));

        Add(intVal,name);
    }
}

// Checks/unchecks items based on the current value of the enum variable
private void ApplyEnumValue()
{
    int intVal = (int)Convert.ChangeType(enumValue, typeof(int));
    UpdateCheckedItems(intVal);

}
        
// Checks/Unchecks items depending on the give bitvalue
protected void UpdateCheckedItems(int value)
{

    isUpdatingCheckStates = true;

    // Iterate over all items
    for(int i=0;i<Items.Count;i++)
    {
        FlagCheckedListBoxItem item = Items[i] as FlagCheckedListBoxItem;

        // If the bit for the current item is on in the bitvalue, check it
        if( (item.value & value)== item.value && item.value!=0)
            SetItemChecked(i,true);
        // Otherwise uncheck it
        else
            SetItemChecked(i,false);
    }

    isUpdatingCheckStates = false;

}

重写CheckListBoxOnItemCheck函数,以便在选中或取消选中任何项目时更新所有其他项目。

protected override void OnItemCheck(ItemCheckEventArgs e)
{
    base.OnItemCheck(e);

    if (isUpdatingCheckStates)
        return;

    // Get the checked/unchecked item
    FlagCheckedListBoxItem item = Items[e.Index] as FlagCheckedListBoxItem;
    // Update other items
    UpdateCheckedItems(item, e.NewValue);
}

// Updates items in the checklistbox
// composite = The item that was checked/unchecked
// cs = The check state of that item
protected void UpdateCheckedItems(FlagCheckedListBoxItem composite, 
                                  CheckState cs)
{

    // If the value of the item is 0, call directly.
    if(composite.value==0)
        UpdateCheckedItems(0);


    // Get the total value of all checked items
    int sum = 0;
    for(int i=0;i<Items.Count;i++)
    {
        FlagCheckedListBoxItem item = Items[i] as FlagCheckedListBoxItem;

        // If item is checked, add its value to the sum.
        if(GetItemChecked(i))
            sum |= item.value;
    }

    // If the item has been unchecked, remove its bits from the sum
    if(cs==CheckState.Unchecked)
        sum = sum & (~composite.value);
    // If the item has been checked, combine its bits with the sum
    else
        sum |= composite.value;

    // Update all items in the checklistbox based on the final bit value
    UpdateCheckedItems(sum);

}

最后,当用户完成属性编辑后,GetCurrentValue方法用于返回CheckListBox中所有选中项目对应的位值。

// Gets the current bit value corresponding to all checked items
public int GetCurrentValue()
{
    int sum = 0;

    for(int i=0;i<Items.Count;i++)
    {
        FlagCheckedListBoxItem item = 
                   Items[i] as FlagCheckedListBoxItem;

        if( GetItemChecked(i))
            sum |= item.value;
    }

    return sum;
}

使用代码

在您自己的项目中使用此代码非常容易。只需将FlagEnumEditor.cs文件添加到您的项目中,然后按如下方式将 UI 类型编辑器应用于您的枚举或属性即可

[Editor(typeof(Utils.FlagEnumUIEditor), 
        typeof(System.Drawing.Design.UITypeEditor))]

源代码 zip 文件包含一个 Visual Studio .NET 解决方案,其中包含一个 Windows 应用程序项目。要查看FlagEnumUIEditor的运行情况,只需编译并运行此解决方案即可。主窗体有一个属性网格,该网格被分配了一个TestObject类型的对象,这只是一个仅用于演示目的的虚拟类型。TestObject具有三个属性,所有属性都是标志枚举类型,即

  • TestEnum:为演示目的而定义的标志枚举。包含作为枚举的两个其他标志成员的组合的枚举值。
  • SecurityPermissionFlag:来自System.Security.Permissions命名空间的标志枚举。
  • FontStyle:来自System.Drawing命名空间的标志枚举。
© . All rights reserved.