В дополнение к некоторым синтаксическим ошибкам и ошибкам компилятора, основная проблема, как упомянуто в комментарии, заключается в том, что ваш метод 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
.