Реализация конвертера типов для выпадающих элементов определенного типа - PullRequest
0 голосов
/ 12 ноября 2018

Пользовательский контроль, который будет использовать конвертер типов

Public Class MYControl : Usercotrol 
{

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

Тип для отображения в раскрывающемся окне свойств

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

Как мне реализовать конвертер типов для этого, это то, что я пытался без успеха

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 Ответ

0 голосов
/ 13 ноября 2018

В дополнение к некоторым синтаксическим ошибкам и ошибкам компилятора, основная проблема, как упомянуто в комментарии, заключается в том, что ваш метод ConvertFrom ожидает возврата ListItem. Хотя это то, что вы предоставляете в StandardValuesCollection, дизайнер не имеет никакого представления о вашем типе.

Разработчику нужна строка для выпадающего списка, и в этом случае будет использоваться ваш метод ToString(). Но вы вернете эту строку для конвертации / регидратации.

Вы также, вероятно, хотите украсить свой Type атрибутом TypeConverter, если хотите, чтобы он ассоциировался со всеми его использованием. Декорирование только свойства UserControl означает, что использование имеет конвертер. Это затрудняет отладку.

Я также использовал идиоматическое имя для конвертера.

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

Основная проблема в Can/ConvertFrom:

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

Дизайнер использует имена (строки) для раскрывающегося списка и string, пользователь выбирает строку, и это то, что вы получите обратно для преобразования, никогда ListItem.

Конвертер также должен переопределить GetStandardValuesExclusive - пользователи не могут придумывать или печатать на новом языке, единственные допустимые - нет?

Другие изменения в коде TypeConverter включают в себя:

  • Использование List, а не ArrayList, которое устарело
  • Удалите new из переопределений, чтобы он скомпилировал
  • StandardValuesCollection просто должен быть набором строк, поэтому я изменил его, чтобы получить имена из списка.

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

В ConvertFrom вам просто нужно найти возвращаемое отображаемое имя, найти связанный ListItem в коллекции и вернуть его. FirstOrDefault никогда не должен завершаться ошибкой и возвращать значение по умолчанию (ноль), поскольку вы работаете с exclusive StandardValuesCollection.

...