Implementing type converter for specific type dropdown items

蹲街弑〆低调 提交于 2021-02-11 14:56:33

问题


The usercontrol that will use the type converter

Public Class MYControl : Usercotrol 
{

private ListItem _Language;
[TypeConverter(typeof(LanguageEditor))]
public ListItem Language
    {
        get
        {
            return _Language;
        }
        set
        {
            _Language= value;
        }
    }
}

The type to list in the dropdown property window

public class ListItem
{
    private string _Name;
    public string Name
    {
        get
        {
            return _Name;
        }
        set
        {
            _Name = value;
        }
    }
    private string _Value;
    public string Value
    {
        get
        {
            return _Value;
        }
        set
        {
            _Value = value;
        }
    }
    public ListItem(string Name, string value)
    {
        _Value = value;
        _Name = Name;
    }

    public override string ToString()
    {
        return this._Name;
    }
}

How do i implement the type converter for this, this is what i tried without success

public class LangEditor : TypeConverter
{
    private ArrayList values;

    public LangEditor()
    {
        // Initializes the standard values list with defaults.
        values = new ArrayList();
        foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures))

            values.Add(new ListItem(ci.DisplayName, ci.Name));
    } // New

    // Indicates this type converter provides a list of standard values.
    public new override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
    {
        return true;
    } // GetStandardValuesSupported

    // Returns a StandardValuesCollection of standard value objects.
    public new override System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(System.ComponentModel.ITypeDescriptorContext context)
    {
        // Passes the local value array.
        StandardValuesCollection svc = new StandardValuesCollection(values);
        return svc;
    } 

    public new override bool CanConvertFrom(System.ComponentModel.ITypeDescriptorContext context, System.Type sourceType)
    {
        var propItem = context.Instance as ListItem;
        return propItem != null && TypeDescriptor.GetConverter(typeof(ListItem)).CanConvertFrom(context, sourceType) || base.CanConvertFrom(context, sourceType);
    } // CanConvertFrom

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        var propItem = context.Instance as ListItem;

        if (propItem != null)
            return TypeDescriptor.GetConverter(typeof(ListItem)).ConvertFrom(context, culture, value);
        else
            return base.ConvertFrom(context, culture, value, ListItem);
    }
}

回答1:


In addition to some syntax and compiler errors the main issue, as mentioned in a comment, is that your ConvertFrom method expects to get back a ListItem. Even though that is what you provide in the StandardValuesCollection, the designer has no idea about your Type.

The designer needs a string for the drop down list, and in this case will use your ToString() method. But you are going to get back that string to convert/rehydrate.

You also probably want to decorate your Type with the TypeConverter attribute if you want it associated with all uses of it. Decorating only the UserControl property means just that usage has a converter. It makes it hard to debug.

I also used an idiomatic name for the converter.

//Public Class MYControl : Usercotrol 
public class MYControl : UserControl 
{
    public ListItem Language {get; set;}
}

// Associate the TypeConverter with the Type, not property
[TypeConverter(typeof(ListItemConverter))]
public class ListItem
{
    public string Name {get; set;}
    public string Value {get; set;}

    // serialization will need this
    public ListItem()
    { }

    public ListItem(string name, string value)
    {
        Value = value;
        Name = name;
    }

    public override string ToString()
    {
        return this.Name;
    }
}

The main problem is in Can/ConvertFrom:

 var propItem = context.Instance as ListItem;
 if (propItem != null)
      ...

The designer uses the names (strings) for the drop down and string, the user picks a string and that is what you will get back to convert, never a ListItem.

The converter should also override GetStandardValuesExclusive - users cannot make up or type in a new language, those supplied are the only legal ones, no?

Other changes in the TypeConverter code include:

  • Using a List and not ArrayList which is obsolete
  • Remove new from the overrides so it will compile
  • The StandardValuesCollection just needs to be a string collection, so I changed it to get the names from the list.

public class ListItemConverter : TypeConverter
{
    private List<ListItem> languages;

    public ListItemConverter()
    {
        // Initializes the standard values list with defaults.
        languages = new List<ListItem>();

        foreach (CultureInfo ci in CultureInfo.GetCultures(CultureTypes.AllCultures))
        {
            languages.Add(new ListItem(ci.DisplayName, ci.Name));
        }
    } 

    // Indicates this type converter provides a list of standard values.
    public override bool GetStandardValuesSupported(System.ComponentModel.ITypeDescriptorContext context)
    {
        return true;
    } 

    public override StandardValuesCollection GetStandardValues(System.ComponentModel.ITypeDescriptorContext context)
    {
        // Passes the local array.
        StandardValuesCollection svc = new StandardValuesCollection(languages);
        return svc;
    } 

    public override bool CanConvertFrom(ITypeDescriptorContext context, 
                                          System.Type sourceType)
    {
        if (sourceType == typeof(string))
        {
            // where the debug code goes
            return true;
        }
        else
            return base.CanConvertFrom(context, sourceType);
    } 

    // ADDED: the list is exclusive - no new entries allowed
    public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
    {
        return true;
    }

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        if(value is string)
        {
            ListItem item = (ListItem)languages.
                        FirstOrDefault( q => (string.Compare(q.Name, value.ToString(),true) == 0));
            return item;
        }
        else
            return base.ConvertFrom(context, culture, value);
    }
}

In ConvertFrom, you simply need to look up the display name you get back, find the related ListItem in the collection and return it. FirstOrDefault ought never fail and return the Default (null) since you are working from an exclusive StandardValuesCollection.



来源:https://stackoverflow.com/questions/53254157/implementing-type-converter-for-specific-type-dropdown-items

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!