问题
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 notArrayList
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