问题
The scenario
Suppose I have the following two model classes:
public class ProductColor
{
public long Id { get; set; }
public string Name { get; set; }
}
public class Product
{
public long Id { get; set; }
public string Name { get; set; }
public long ProductColorId { get; set; }
public virtual ProductColor ProductColor { get; set; }
}
Now in a form for creating a new product, I might have this line for the color field...
@Html.EditorFor(model => model.ProductColor)
I want this to generate a drop-down of colors, so I create a custom editor template...
@model MyProject.Models.ProductColor
@using (var db = new MyProject.Models.MyDbContext())
{
@Html.DropDownList("", new SelectList(db.ProductColors, "Id", "Name", Model))
}
Up to here, this works. But now if I submit this create form, I get this validation error:
The parameter conversion from type 'System.String' to type 'MyProject.Models.ProductColor' failed because no type converter can convert between these types.
Of course this is because the HTTP request contains the color ID as a string (e.g. "1"
) and one would need some code to turn that into an actual ProductColor
instance. So I wrote a TypeConverter
...
[TypeConverter(typeof(ProductColor.PCTypeConverter))]
public class ProductColor
{
public long Id { get; set; }
public string Name { get; set; }
public class PCTypeConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
return sourceType == typeof(string) ? true : base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value.GetType() == typeof(string))
using (var db = new MyDbContext())
return db.ProductColors.Find(Convert.ToInt64(value));
return base.ConvertFrom(context, culture, value);
}
}
}
Now submitting the request works fine as expected, but the custom editor template no longer does. It just doesn’t get invoked. The system thinks that my type is basically like string and just generates a textbox.
The problem
I cannot get both to work. Either I have a type converter, in which case I don’t get the drop-down (because the custom editor template never gets invoked), or I don’t have a type converter, in which case validation fails when the request is submitted.
What is the correct solution to this?
回答1:
Instead of
@Html.EditorFor(model => model.ProductColor)
refer to the ID field:
@Html.EditorFor(model => model.ProductColorId)
Annotate that ID field with a
UIHint
attribute containing the name of the type (more precisely, the name of the custom editor template):public class Product { public long Id { get; set; } public string Name { get; set; } [UIHint("ProductColor")] public long ProductColorId { get; set; } public virtual ProductColor ProductColor { get; set; } }
Change the custom editor template so that it uses
long?
as the model type:@model long? @using (var db = new MyProject.Models.MyDbContext()) { @Html.DropDownList("", new SelectList(db.ProductColors, "Id", "Name", Model)) }
Get rid of the TypeConverter.
来源:https://stackoverflow.com/questions/9297565/cannot-use-typeconverter-and-custom-display-editor-template-together