如何创建类似于 Html.DisplayFor 的 html 帮助器方法,该方法将在自定义文件夹中查找

发布于 2024-11-27 10:42:47 字数 1530 浏览 0 评论 0原文

我的模型基于抽象基类,如下所示:

  • InsurancePolicy(所有保单的基本抽象类)
    • 车辆保险单
      • Abc保险保单
      • DefInsurancePolicy
    • 家庭保险单
    • 人寿保险单
    • ...等

在控制器中,我有以下用于通常详细信息/列表场景的代码:

    public ActionResult Details(int id) {
        // actual type is one of the concrete implementations
        InsurancePolicy policy = _repository.Get(id);
        return View(policy);
    }

    public ActionResult List() {
        // a list of concrete implementations
        IList<InsurancePolicy> policies = _repository.GetLatest(20);
        return View(policies);
    }

Details.chstml仅调用@Html.DisplayForModel()和ASP .NET MVC 实际上根据实际类型(其中之一)从 Shared/DisplayTemplates 中选择正确的部分视图子类)。此外,如果找不到具有该名称的视图,它将回退到基类模板 InsurancePolicy.cshtml。例如,它会为 AbcInsurancePolicy 模型选择 VehicleInsurancePolicy.cshtml,因为找不到 AbcInsurancePolicy.cshtml;对于 HomeInsurancePolicy,它将选择默认的 InsurancePolicy.cshtml,因为 DisplayTemplates 文件夹中没有 HomeInsurancePolicy.cshtml。它允许我添加其他 InsurancePolicy 子类型,而无需首先创建显示模板。

我希望列表视图有类似的行为。在 List.cshtml razor 视图中,我只会循环遍历我的项目,并调用类似 Html.ListItemFor(...)

<ul>
@foreach (var policy in Model) {
    @Html.ListItemFor(_ => policy)
 }
</ul>

如何创建 Html.ListItemFor html 帮助器,它将查看 ListItemTemplates 文件夹并与 Html 完全相同。显示为? 还有其他方法可以做到这一点吗?

笔记: Html.DisplayFor(m => m.Property, templateName) 不起作用,它必须根据项目类型选择模板名称,递归回退到基类模板,直到找到某些内容。

My model is based on an abstract base class, and it looks like this:

  • InsurancePolicy (base abstract class for all policies)
    • VehicleInsurancePolicy
      • AbcInsurancePolicy
      • DefInsurancePolicy
    • HomeInsurancePolicy
    • LifeInsurancePolicy
    • ... etc

In a controller I have the following code for the usual detalis / list scenarios:

    public ActionResult Details(int id) {
        // actual type is one of the concrete implementations
        InsurancePolicy policy = _repository.Get(id);
        return View(policy);
    }

    public ActionResult List() {
        // a list of concrete implementations
        IList<InsurancePolicy> policies = _repository.GetLatest(20);
        return View(policies);
    }

The Details.chstml only calls @Html.DisplayForModel(), and ASP.NET MVC actually selects the correct partial view from Shared/DisplayTemplates based on the actual type (one of the subclasses). Moreover, if it cannot find a view with that name, it falls back to the base class template, InsurancePolicy.cshtml. For example, it would select VehicleInsurancePolicy.cshtml for a AbcInsurancePolicy model, because no AbcInsurancePolicy.cshtml is found; for HomeInsurancePolicy it will select the default InsurancePolicy.cshtml since there is no HomeInsurancePolicy.cshtml in DisplayTemplates folder. It allows me to add other InsurancePolicy subtypes, without creating a display template in the first place.

I want to have similar behavior for a list view. In List.cshtml razor view I would only loop over my items, and call something like Html.ListItemFor(...)

<ul>
@foreach (var policy in Model) {
    @Html.ListItemFor(_ => policy)
 }
</ul>

How do I create a Html.ListItemFor html helper, that would look into a ListItemTemplates folder and act exactly as Html.DisplayFor ?
Is there any other way to do this?

Notes:
Html.DisplayFor(m => m.Property, templateName) wouldn't work, it must choose the template name based on item type, fall back recursively to base class template until it finds something.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鱼窥荷 2024-12-04 10:42:47

其工作方式是根据视图引擎中定义的一组视图位置来查找模板。

您可以做的是通过继承 RazorViewEngine 并重写来创建自己的 ViewEngine,

   public override ViewEngineResult FindPartialView(
        ControllerContext controllerContext, 
        string partialViewName, 
        bool useCache)

这样您就可以提出自己的全新约定,并使用控制器上下文中的值来决定要查找的视图。

你可能会做这样的事情(尽管可能需要调整它以完全适合你的场景)

 public override ViewEngineResult FindPartialView(
    ControllerContext controllerContext, 
    string partialViewName, 
    bool useCache)
{
    ViewEngineResult result = null;

    //Get the TypeName that you want to look for
     var typeName = controllerContext.Controller.ViewData.Model.GetType().Name;

     result = base.FindPartialView(
             controllerContext, typeName, useCache);


    //Fall back to default search path if no other view has been selected  
    if (result == null || result.View == null)
    {
        result = base.FindPartialView(
            controllerContext, partialViewName, useCache);
    }

    return result;  
}

The way this works is that templates are found based on a set of view locations defined in the view engine.

What you can do is create your own ViewEngine by inheriting from the RazorViewEngine and overriding the

   public override ViewEngineResult FindPartialView(
        ControllerContext controllerContext, 
        string partialViewName, 
        bool useCache)

this way you can come up with your own completely new convention and use the values in the controller context to decide what view to look for.

You could probably do something like this (altho might need to tweak it to suit your scenario exactly)

 public override ViewEngineResult FindPartialView(
    ControllerContext controllerContext, 
    string partialViewName, 
    bool useCache)
{
    ViewEngineResult result = null;

    //Get the TypeName that you want to look for
     var typeName = controllerContext.Controller.ViewData.Model.GetType().Name;

     result = base.FindPartialView(
             controllerContext, typeName, useCache);


    //Fall back to default search path if no other view has been selected  
    if (result == null || result.View == null)
    {
        result = base.FindPartialView(
            controllerContext, partialViewName, useCache);
    }

    return result;  
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文