Каков предпочтительный способ стандартизации сложных представлений HTML для типов данных?

У меня есть такой код, который я повторяю во многих представлениях редактирования MVC. В этом примере мы отображаем флажок по умолчанию, но подобное повторение встречается и с другими типами ввода.

<div class="form-group">
    @Html.LabelFor(model => model.IsLive, htmlAttributes: new { @class = "control-label col-md-3" })
    <div class="col-md-8 checkbox">
        <div class="col-xs-1">
            @Html.EditorFor(model => model.IsLive)
        </div>
        <div class="col-xs-10">
            @Html.CheckboxLabelFor(model => model.IsLive)
        </div>
    </div>
    <a class="infoonclick col-md-1" title="@Html.DisplayNameFor(model => model.IsLive)" data-content="@Html.DescriptionFor(model => model.IsLive)">
        <span class="fa fa-info-circle"></span>
    </a>
</div>

Мне интересно, как лучше всего СУХОЙ и стандартизировать это?

Я хочу сделать что-то вроде @Html.DefaultCheckboxEditorFor(model => model.IsLive)

Я попытался создать собственный HtmlHelper, но мне показалось, что для этого требовалось слишком много жестко закодированных строк.

Скорее, я считаю, что для этого мне следует использовать EditorTemplates, но я не могу понять синтаксис правильно. Модель для представления - это bool, но мне нужно получить специфические для свойства вещи, такие как отображаемое имя и описания.

 @model bool


<div class="form-group">
    @Html.LabelFor(model => model.IsLive, htmlAttributes: new { @class = "control-label col-md-3" })
    <div class="col-md-8 checkbox">
        <div class="col-xs-1">
            @Html.EditorFor(model => model.IsLive)
        </div>
        <div class="col-xs-10">
            @Html.CheckboxLabelFor(model => model.IsLive)
        </div>
    </div>
    <a class="infoonclick col-md-1" title="@Html.DisplayNameFor(model => model.IsLive)" data-content="@Html.DescriptionFor(model => model.IsLive)">
        <span class="fa fa-info-circle"></span>
    </a>
</div>

person Martin Hansen Lennox    schedule 05.05.2015    source источник
comment
В шаблоне ваша модель bool, поэтому она должна быть @Html.LabelFor(m=> m) и т. Д.   -  person    schedule 05.05.2015
comment
Также не уверен, почему вы думаете, что создание вспомогательного метода расширения html является проблемой. В этом ответе приведен пример чего-то, что довольно близко к вашему выводу. .   -  person    schedule 05.05.2015
comment
О'кей, в этом есть смысл - спасибо. Проблема с помощником html заключается в том, что там слишком много классов, которые потенциально могут измениться. Мне кажется неправильным жесткое кодирование их в помощника.   -  person Martin Hansen Lennox    schedule 05.05.2015
comment
Все, что делает помощник, - это то, что делает ваш шаблон, но это означает, что вы можете скомпилировать его в отдельную dll и повторно использовать в нескольких проектах. У обоих подходов есть свои достоинства, все зависит от того, что вы хотите делать и как используете. Но, конечно, если вы хотите гибкости, чтобы иметь возможность изменять атрибуты, такие как имена классов, шаблон был бы лучше.   -  person    schedule 05.05.2015
comment
Я еще не достаточно хорош, чтобы моя работа была скомпилирована в библиотеки DLL!   -  person Martin Hansen Lennox    schedule 05.05.2015


Ответы (1)


У меня есть проект, в котором большинство моих представлений выглядят так: (Это также работает с многоуровневыми глубокими сложными объектами, но не с любым типом коллекции, например IEnumerable, хотя его можно изменить для этого)

<h3>Edit existing page</h3>

<div class="col-xs-12">
    @using (Html.BeginForm("Edit", "Page", FormMethod.Post, new { role = "role" }))
    {
      @Html.EditorForModel()
      <input type="submit" value="Save" class="btn btn-primary" />
    }
</div>

Я думаю, это круто. Итак, модель выглядит так:

public class PageEditViewModel
{
    [Editable(false)]
    [DisplayName("Page Id")]
    public Guid Id { get; set; }

    [Editable(false)]
    [DisplayName("Url to resource (format: '/my-resource' or '/sub/resource)'")]
    public string Url { get; set; }

    [Required]
    [MaxLength(50, ErrorMessage = "Maximum Length of 50 Exceeded.")]
    [DisplayName("Title for page (must match Url ex: 'My Resource' or 'Sub Resource'")]
    public string PageTitle { get; set; }

    [MaxLength(int.MaxValue, ErrorMessage = "Content Exceeded Maximum Length")]
    [DataType(DataType.MultilineText)]
    public string Content { get; set; }
}

У меня есть несколько шаблонов редактора:

\ Views \ Shared \ EditorTemplates \ multilinetext.cshtml

@model object
@{
  var htmlAttributes = this.ViewData.ModelMetadata.GetHtmlAttributes();
}

<div class="form-group @Html.ErrorClassFor(m => m, "has-error")">
    @Html.LabelFor(m => m, new { @class = "control-label" })
    <div class="controls">
        @Html.TextAreaFor(
            m => m,
            8, 8,
            htmlAttributes)
        @Html.ValidationMessageFor(m => m, null, new { @class = "help-block" })
    </div>
</div>

И все это волшебным образом работает с модифицированной версией object.cshtml:

@model object

@using System.Text;
@using System.Data;

@{
  ViewDataDictionary viewData = Html.ViewContext.ViewData;
  TemplateInfo templateInfo = viewData.TemplateInfo;
  ModelMetadata modelMetadata = viewData.ModelMetadata;

  System.Text.StringBuilder builder = new StringBuilder();

  string result;

  // DDB #224751
  if (templateInfo.TemplateDepth > 2)
  {
     result = modelMetadata.Model == null ? modelMetadata.NullDisplayText
                                            : modelMetadata.SimpleDisplayText;
  }

  foreach (var prop in modelMetadata.Properties.Where(pm =>
     pm.ShowForEdit
        //&& pm.ModelType != typeof(System.Data.EntityState)
     && !templateInfo.Visited(pm)
     )
     .OrderBy(pm => pm.Order))
  {

     //Type modelType =  Model.GetType();
     Type modelType = modelMetadata.ModelType;
     System.Reflection.PropertyInfo pi = modelType.GetProperty(prop.PropertyName);
     System.ComponentModel.DataAnnotations.DisplayAttribute attribute = pi.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute), false).FirstOrDefault() as System.ComponentModel.DataAnnotations.DisplayAttribute;

     if (attribute != null
         && !string.IsNullOrWhiteSpace(attribute.GetGroupName()))
     {
        //builder.Append(string.Format("<div>{0}</div>", attribute.GetGroupName()));
        builder.Append(Html.Partial("Partial-GroupName", attribute.GetGroupName()));
     }

     builder.Append(Html.Editor(prop.PropertyName, prop.TemplateHint ?? prop.DataTypeName).ToHtmlString());
  }

  result = builder.ToString();
}
@Html.Raw(result)

Пример вывода:

EditForModel

Мои шаблоны EditFor являются версиями MacawNL BootstrapEditorTemplates (к которому я не имею отношения).

person Erik Philips    schedule 05.05.2015
comment
Я тоже думаю, что это круто! Спасибо за подробный ответ и примеры кода, мне очень полезно увидеть, как все это сочетается друг с другом. - person Martin Hansen Lennox; 05.05.2015
comment
Закомментированные части object.cshtml, в которых вы внесли изменения по сравнению с параметрами по умолчанию? - person Martin Hansen Lennox; 05.05.2015
comment
Некоторые да некоторые нет. Он трансформировался из поколения в поколение (начинался как MVC2 object.ascx). - person Erik Philips; 05.05.2015