MVC4 ViewData.TemplateInfo.HtmlFieldPrefix создает дополнительную точку

Я пытаюсь получить правильное имя ввода, чтобы набор объектов в моей модели представления мог быть связан.

   @{ViewData.TemplateInfo.HtmlFieldPrefix = listName;}
            @Html.EditorFor(m => m, "DoubleTemplate", new { 
                Name = listName,
                Index = i,
                Switcher = (YearOfProgram >= i +1)
            })

Как вы можете видеть здесь, я передаю listName в качестве префикса для моего шаблона, значение listName = MyItems.

И вот мой шаблон:

@model Web.Models.ListElement

@if (ViewData["Switcher"] != null)
{
    
    var IsVisible = (bool)ViewData["Switcher"];
    var index = (int)ViewData["Index"];
    var thisName = (string)ViewData["Name"] + "[" + index + "].Value";
    var thisId = (string)ViewData["Name"] + "_" + index + "__Value";
    if (IsVisible)
    {
        @*<input type="text" value="@Model.Value" name="@thisName" id ="@thisId" class="cell@(index + 1)"/>*@
        @Html.TextBoxFor(m => m.Value, new { @class ="cell" + (index + 1)})
        @Html.ValidationMessageFor(m => m.Value)
    }
}

но я обнаружил, что сгенерированное имя становится таким: MyItems.[0].Value

Он имеет одну дополнительную точку. Как я могу избавиться от этого?

Между прочим, я попытался вручную указать имя внутри шаблона и обнаружил, что имя переопределяется помощником Html.

Обновлять

Причина, по которой я должен вручную установить HtmlFieldPrefix, заключается в том, что имя свойства (MyItems, которое представляет собой список объектов) будет потеряно, когда MyItems будет передан из основного представления в частичное представление. К тому времени, как частичное представление вызвало мой шаблон и передало его в один объект в MyItems, сам шаблон не имеет возможности определить имя MyItems, так как оно было потеряно с момента последней передачи.

Вот почему я должен вручную установить имя префикса поля html. И я даже пытался использовать что-то похожее на отражение (но не переизбрание, я забыл имя), чтобы проверить имя переданного объекта и обнаружил, что он возвращает модель.


Обновление 2

Я попробовал подход Стивена и не могу найти html-помощник PartialFor().

введите здесь описание изображения

Я даже пытался использовать это в своем основном представлении:

Html.Partial(Model, "_MyPartialView");

В частичном представлении:

@model MvcApplication1.Models.MyModel
<h2>My Partial View</h2>


@Html.EditorFor(m => m.MyProperty)

Вот мой шаблон:

@model  MvcApplication1.Models.ListElement

@Html.TextBoxFor(m => m.Value)

Вот моя модель:

 public class MyModel
    {
        private List<ListElement> myProperty;
        public List<ListElement> MyProperty
        {
            get
            {
                if (myProperty == null)
                {
                    this.myProperty = new List<ListElement>() { new ListElement() { Value = 12 }, new ListElement() { Value = 13 }, new ListElement() { Value = 14 }, new ListElement() { Value = 15 }, };
                }
                return this.myProperty;
            }
            set
            {
                this.myProperty = value;
            }
        }
    }

    public class ListElement
    {
        [Range(0, 999)]
        public double Value { get; set; }
    }

А вот мой контроллер:

public ActionResult MyAction()
{
    return View(new MyModel());
}

Он генерирует для меня только необработанный текст (12131415) вместо требуемого текстового поля, заполненного 12 13 14 15.

Но если я указал имя шаблона, он выдает исключение:

The template view expecting ListElement, and cannot convert
List<ListElement> into ListElement.

person Franva    schedule 08.09.2014    source источник
comment
Немного сложно понять, чего вы пытаетесь достичь, переопределяя поведение по умолчанию. У вашего режима есть свойство public ListElement MyItems { get; set; }? Если нет, как бы вы привязали это к обратной передаче? У вас есть еще EditorTemplate для typeof ListElement?   -  person    schedule 08.09.2014
comment
привет @StephenMuecke да, у моей модели есть MyItems (у MyViewModel есть MyItems). Я привязываю MyViewModel к странице MyView.cshtml, которая использует PartialView _MyPartialView, это частичное представление использует шаблон. И я говорю о потере имени свойства в этом шаблоне. Я нашел решение, возможно, оно не самое лучшее.   -  person Franva    schedule 09.09.2014
comment
Но вам не нужно устанавливать значение HtmlFieldPrefix. Если вы используете вас EditorTemplate правильно, MVC сделает это за вас (вы не должны использовать перегрузку, которая принимает имя шаблона).   -  person    schedule 09.09.2014
comment
привет @StephenMuecke Я обновил свой пост в соответствии с вашим вопросом, пожалуйста, посмотрите мою часть обновления. ваше здоровье   -  person Franva    schedule 09.09.2014
comment
Вскоре я опубликую ответ, показывающий, как вы можете это сделать, но я немного не уверен, что Switcher но мы можем разобраться с этим после   -  person    schedule 09.09.2014
comment
привет @StephenMuecke Switcher используется для определения, показывать ли это текстовое поле или нет. И спасибо, с нетерпением жду правильного способа сделать это :)   -  person Franva    schedule 09.09.2014
comment
Ответ опубликован. Откуда берется значение Switcher. Это свойство ListElement или что-то основано на свойстве основной модели? - возможно, ответьте в ответе, и я обновлю его на основе вашего ответа   -  person    schedule 09.09.2014


Ответы (4)


Нет необходимости устанавливать значение HtmlFieldPrefix. MVC правильно назовет элементы, если вы используете EditorTemplate на основе типа свойства (и без имени шаблона).

Предполагаемые модели

public class ListElement
{
  public string Value { get; set; }
  ....
}

public class MyViewModel
{
  public IEnumerable<ListElement> MyItems { get; set; }
  ....
}

Шаблон редактора (ListElement.cshtml)

@model YourAssembly.ListElement
@Html.TextBoxFor(m => m.Value)

Основной вид

@model YourAssembly.MyViewModel
...
@Html.EditorFor(m => m.MyItems) // note do not specify the template name

Это будет отображать

<input type="text" name="MyItems[0].Value" ...>
<input type="text" name="MyItems[1].Value" ...>
....

Если вы хотите сделать это с помощью частичного, вы можете просто передать всю модель частичному

MyPartial.cshtml

@model @model YourAssembly.MyViewModel
@Html.EditorFor(m => m.MyItems)

и в основном виде

@Html.Partial("MyPartial")

или создайте метод расширения

public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper,
  Expression<Func<TModel, TProperty>> expression, string partialViewName)
  {
    string name = ExpressionHelper.GetExpressionText(expression);
    object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
    var viewData = new ViewDataDictionary(helper.ViewData)
    {
      TemplateInfo = new System.Web.Mvc.TemplateInfo { HtmlFieldPrefix = name }
    };
    return helper.Partial(partialViewName, model, viewData);
  }
}

и использовать как

@Html.PartialFor(m => m.MyItems, "MyPartial")

и в частичном

@model IEnumerable<YourAssembly.ListElement>
@Html.EditorFor(m => m)
person Community    schedule 09.09.2014
comment
привет Стивен, спасибо за вашу помощь. Но ситуация другая. Основной вид ---> Частичный вид (передается в MyItems) ---> MyTemplate (передается в одном объекте в MyItems, например, MyItems[i]) Я пытался использовать их обычным способом, но обнаружил, что имя MyItems было потерян, и он стал [0].Value. О, кстати, почему бы не указать имя шаблона??? - person Franva; 09.09.2014
comment
Вы все еще можете сделать это, используя частичное (я обновлю ответ). Причина того, что вы не используете перегрузку с именем шаблона, заключается в том, что вы теряете индексацию по умолчанию для имени - см. custom-editor-templates-with-ienumerable-models-in#comment40210985_25333332">этот вопрос для более подробного объяснения - person ; 09.09.2014
comment
ха хорошо выглядит. Я попробую и дам вам знать, как это происходит. Спасибо :) - person Franva; 09.09.2014
comment
Привет, Стивен, я попробовал твой подход. Я даже не могу найти помощника @Html.PartialFor() в своем MVC. Я использую MVC4, какая у вас версия? - person Franva; 15.09.2014
comment
@Franva, PartialFor() - это метод расширения, который я создал для вас - посмотрите код в моем ответе - блок кода, который начинается с public static MvcHtmlString PartialFor<TModel ... - person ; 15.09.2014
comment
Привет, Стивен, так что, если я не использую метод расширения, который вы создали для меня, этот подход не сработает? - person Franva; 15.09.2014
comment
Правильно, обратите внимание, что я дал 2 варианта выше (вы всегда можете передать всю модель частичному), но метод расширения лучше, ИМХО, потому что это повторно используемый фрагмент кода. - person ; 15.09.2014
comment
У меня была похожая проблема с асинхронно вызываемым частичным представлением, и я нашел примеры в этом ответе очень полезными и информативными. Для моей конкретной ситуации мне все еще нужно было установить HtmlFieldPrefix (см.: stackoverflow.com/questions/6617768/), но снова этот ответ улучшил мое понимание и помог мне отладить мою проблему. Престижность примерно через 3,5 года - person LoJo; 22.02.2018
comment
@stephen-muecke Спасибо за этот метод расширения! Это намного чище, чем то, куда я изначально направлялся, чтобы решить аналогичную проблему. - person Ken Palmer; 11.04.2018

  1. Назовите свой частичный путь следующим образом:
@Html.Partial("_SeatTypePrices", Model.SeatTypePrices, new ViewDataDictionary
{
    TemplateInfo = new TemplateInfo() {HtmlFieldPrefix = nameof(Model.SeatTypePrices)}
})
  1. Частичный вид:
@model List
@Html.EditorForModel()
  1. Реализация шаблона редактора:

    @using Cinema.Web.Helpers
    @model Cinema.DataAccess.SectorTypePrice
    @Html.TextBoxFor(x => Model.Price)
    

Таким образом, ваше частичное представление будет содержать список элементов с префиксами. А затем вызовите EditorForModel() из папки EditorTemplates.

person Artem Mazur    schedule 21.03.2016

Я обнаружил, что могу изменить значение HtmlFeildPrefix в своем шаблоне.

Итак, что я сделал для решения своей проблемы, так это просто присвоил правильное значение HtmlFeildPrefix непосредственно в шаблоне, а не на странице, которая вызывает шаблон.

Я надеюсь, что это помогает.

person Franva    schedule 09.09.2014

Если я хочу передать HtmlFieldPrefix, я использую следующую конструкцию:

<div id="_indexmeetpunttoewijzingen">
    @Html.EditorFor(model => model.MyItems, new ViewDataDictionary()
    {
        TemplateInfo = new TemplateInfo()
        {
            HtmlFieldPrefix = "MyItems"
        }
    })
</div>                       
person HBorkhuis    schedule 04.11.2016