Cannot use TypeConverter and custom display/editor template together?

可紊 提交于 2019-12-11 03:45:36

问题


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

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