简体   繁体   中英

How to create a property to store the index of the selected value from another property?

I need help with the following problem:

I have a class with two properties.

private byte m_selectedValue;
public byte SelectedValue
{
  get { return m_selectedValue; }
  set { m_selectedValue = value; }
}

private string[] m_possibleValues;
public string[] PossibleValues
{
  get { return m_possibleValues; }
  set { m_possibleValues = value; }
}

The PossibleValues stores the list of the selectable values. The SelectedValue contains the index of the actually selected value.

In this state the property editor shows the index of the selected value. I would like to select the value using a combobox in the property grid, the same style used with an Enum property. The combobox's list would be populated from the PossibleValues property.

With the help of this article ( http://www.codeproject.com/KB/cpp/UniversalDropdownEditor.aspx ) I have managed to create a custom editor that show the combobox on the property grid with the values from the PossibleValues property. I can also select the value, but still the property grid shows the index of the value instead of the value itself.

This is the modified source of the editor (original is from CodeProject):

public class EnumParamValuesEditor : UITypeEditor
{
    private IWindowsFormsEditorService edSvc;

    public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
    {
        if ((context != null) && (context.Instance != null))
            return UITypeEditorEditStyle.DropDown;
        return UITypeEditorEditStyle.None;
    }

    public override object EditValue(System.ComponentModel.ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        if ((context == null) || (provider == null) || (context.Instance == null))
            return base.EditValue(provider, value);
        edSvc = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));
        if (edSvc == null)
            return base.EditValue(provider, value);
        ListBox lst = new ListBox();
        PrepareListBox(lst, context);
        lst.SelectedIndex = (byte)value;
        edSvc.DropDownControl(lst);
        if (lst.SelectedItem == null)
            value = null;
        else
            value = (byte)lst.SelectedIndex;
        return value;
    }

    private void PrepareListBox(ListBox lst, ITypeDescriptorContext context)
    {
        lst.IntegralHeight = true;
        string[] coll = ((EnumTerminalParam)context.Instance).PossibleValues;
        if (lst.ItemHeight > 0)
        {
            if ((coll != null) && (lst.Height / lst.ItemHeight < coll.Length))
            {
                int adjHei = coll.Length * lst.ItemHeight;
                if (adjHei > 200)
                    adjHei = 200;
                lst.Height = adjHei;
            }
        }
        else
            lst.Height = 200;
        lst.Sorted = true;
        FillListBoxFromCollection(lst, coll);
        lst.SelectedIndexChanged += new EventHandler(lst_SelectedIndexChanged);
    }

    void lst_SelectedIndexChanged(object sender, EventArgs e)
    {
        if (edSvc == null)
            return;
        edSvc.CloseDropDown();
    }

    public void FillListBoxFromCollection(ListBox lb, ICollection coll)
    {
        lb.BeginUpdate();
        lb.Items.Clear();
        foreach (object item in coll)
            lb.Items.Add(item);
        lb.EndUpdate();
        lb.Invalidate();
    }

}

Of course, it needs further modifications to correctly handle some situations (ex. the PossibleValues is empty).

So is it possible to show the PossibleValues[SelectedValue] instead of the SelectedValue in the property editor?

You need to attach a custom TypeConverter to your SelectedValue property and make the PossibleValues non browsable. The TypeConverter will be responsible for showing strings in the PropertyGrid instead of ints. So basically, you need to override CanConvertFrom, CanConvertTo, ConvertFrom and ConvertTo. When you want to get your custom strings, use the context argument passed to these methods and call your PossibleValues property in your target instance. That should make it. Seems you don't need any custom UITypeEditor here.

Instead of two separate properties why not tie them together within a Dictionary type. So much easier to use in this case. With your index as the key and the string[] as values. Just don't limit yourself to a byte for the index.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM