Why is my editor template ignored when I call Edit

2019-07-21 05:08发布

问题:

I have a class called LocalizedString that is defined in an external library that is referenced in my asp.net mvc 3 project.

I have created an editor template called LocalizedString.cshtml in the ~\View\Shared\EditorTemplates folder.

I have the following model

public class Region
{
    public LocalizedString Title { get; set; }
}

I have the following test page:

@model Region

@Html.EditorForModel()
@Html.EditorFor(x => x.Title)

The editor template for LocalizedString is not invoked when I call EditorForModel, but it does render when i explicitly call EditorFor(x => x.Title) so I know that I don't have referral problems.

Why is my editor template ignored when I invoke EditorForModel (or its equivalent EditorFor(x => x))

Updates

I created a new project to reproduce this behavior. I just used the default ASP.NET MVC 3 Internet Application.

Index.cshtml

@model MvcApplication1.Models.Region
@{
    ViewBag.Title = "Home Page";
}

<h2>@ViewBag.Message</h2>
<p>
    To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>

@Html.EditorForModel()

HomeController.cs

using System.Web.Mvc;
using MvcApplication1.Models;

namespace MvcApplication1.Controllers
{
    public class HomeController : Controller
    {
        public ActionResult Index()
        {
            ViewBag.Message = "Welcome to ASP.NET MVC!";

            return View(new Region());
        }
    }
}

Region.cs

namespace MvcApplication1.Models
{
    public class Region
    {
        public Region()
        {
            this.Name = "RegionInstance";
            this.Title = new LocalizedString();
        }

        public string Name { get; set; }

        public LocalizedString Title { get; set; }
    }
}

LocalizedString.cs

namespace MvcApplication1.Models
{
    public class LocalizedString
    {
        public LocalizedString()
        {
            this.Name = "LocalizedStringInstance";
        }

        public string Name { get; set; }
    }
}

If you run this program, the output will only display a text input for the name of the region. The LocalizedString.cshtml content is never output.

I also tried to use UIHint over the Region.Title property, but it still does not display.

回答1:

Turn out that this is the same problem as Html.EditorForModel doesnt render complex types

By default, ASP.NET MVC does not render child complex type as I found out through reflection

private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)
{
  if (metadata.ShowForEdit && metadata.ModelType != typeof (EntityState) && !metadata.IsComplexType)
    return !templateInfo.Visited(metadata);
  else
    return false;
}

Which is called by the ObjectTemplate in System.Web.Mvc.Html.DefaultEditorTemplates.

After checking the behavior of IsComplexType, I found out that a type is complex if it cannot be converted to a string through a TypeConverter. If I create a TypeConverter for my child model, it does render. Although this solution is not ideal and I might just stick with EditorFor instead of EditorForModel.

using System;
using System.ComponentModel;

public class LocalizedStringTypeConverter : TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
    {
        if (sourceType == typeof(string))
        {
            return true;
        }

        return base.CanConvertFrom(context, sourceType);
    }
}


回答2:

We just run into a similar issue. Everything worked fine in the development environment but when the build was installed into a test environment, one of the templates was ignored. It turned out that for some reason in the properties of that particular template "Build action" was "none" instead of "content". No ides why it was that way but fixing that setting fixed the problem.