Property Grid Checkbox List Dropdown

685 Views Asked by At

I am trying to convert a dropdown on a property grid into a check box list dropdown which allows user to select more than one result. At the moment, I have managed to build a list of dropdown options a user can select against but it only allows the user to select one. I want the user to select more than 1 option and the Game_Type field will keep track of what's selected with a comma separating the options like "Shooter, Sports". How can I do this?

enter image description here

The expected control should have a checkbox beside the name like shown below:

enter image description here

My code shown below includes a game class, a type converter for my dropdown and the form which created the object and adds it to the property grid.

public class Game
{
    public string name { set; get; }

    [Browsable(false)]
    public List<string> listOfGameTypes { set; get; }

    [DisplayName("Game Type")]
    [TypeConverter(typeof(Game_Type_Converter))]
    public string Game_Type { get; set; }

    public Game()
    {
        listOfGameTypes = new List<string>();
    }
}

.

public class Game_Type_Converter : TypeConverter
{
    public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
    {
        return true;
    }

    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        var obj = context.Instance as Game;

        if (obj != null)
        {
            List<string> list = new List<string>();
            foreach (String s in obj.listOfGameTypes)
            {
                list.Add(s);
            }
            return new StandardValuesCollection(list);
        }


        return base.GetStandardValues(context);
    }


}

.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        Game g = new Game();
        g.name = "FIFA 22";
        g.listOfGameTypes.Add("Shooter");
        g.listOfGameTypes.Add("Sports");
        g.listOfGameTypes.Add("Action");

        propertyGrid1.SelectedObject = g;
    }
}
1

There are 1 best solutions below

0
Caius Jard On

The following content has been reproduced from https://www.codeproject.com/Articles/13793/A-UITypeEditor-for-easy-editing-of-flag-enum-prope

I am not the author of that article

As the article is quite old, there are doubtless some small improvements that could be made such as use of Enum.HasFlags


enter image description here

Introduction

The design time support in Visual Studio .NET is very good, and makes it very easy to quickly develop forms and user controls. Even so, it has some minor shortcomings - some irritating, and some causing inconvenience. One such shortcoming is the lack of a good way to edit 'flag enum properties' in the design time property browser. Flag enum properties are properties whose type is an enum which has the FlagsAttribute applied to it. This attribute indicates that the enum can be treated as a bit field; that is, a set of flags. An example of such an enum is the FontStyle enum. It contains bit values for the Bold, Italic, and Underline styles, which can be combined together if needed. However, the property grid has no inbuilt support for such flag enums - if you want to specify that your font should be Bold as well as Italic, the only way to do so is to write equivalent code.

This article presents a simple UITypeEditor which can be applied to such flag enums and makes it very easy to edit such properties using the design time property browser.

Background

Before discussing the code, it is necessary to give a brief introduction on what an UI Type Editor is. In situations where the simple string-to-value and value-to-string conversion provided by the property browser is not sufficient or convenient, a UI type editor can be used to provide an advanced UI for editing the property. For example, the Dock and Anchor properties of all controls use a UI type editor for easy editing of the properties. To specify that a property should use a UI type editor, the EditorAttribute is applied to the type of the property or to the property itself. In the first case, the UI type editor is used whenever a property has the type to which the attribute is applied. In the second case, the UI type editor is used only for that property.

The FlagEnumUIEditor class

The UI type editor used for flag enums is called FlagEnumUIEditor, and is derived from UITypeEditor. It is a dropdown style editor, which means that a small drop-down button is displayed in the property browser when the property is selected. When this button is clicked, a control is shown which can be used to edit the property. The FlagEnumUIEditor uses a class derived from CheckedListBox to display the flag enums.

The FlagCheckedListBox class

The FlagCheckedListBox class is derived from CheckedListBox and contains items of type FlagCheckedListBoxItem. Each item has a value and a description for the value corresponding to the values and names of the enum members. The EnumValue property is used to associate an enum value with the 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
     }
}

The FillEnumMembers and ApplyEnumValue functions are as follows:

// 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;

}

The OnItemCheck function of CheckListBox is overridden to update all other items whenever any item is checked or unchecked:

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);

}

Finally, when the user is done editing the property, the GetCurrentValue method is used to return the bit value corresponding to all checked items in the 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;
}

Using the code

Using the code in your own project is very easy. Simply add the FlagEnumEditor.cs file to your project, and apply the UI type editor to your enums or properties as follows:

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