MVC3 Пользовательский HTMLHelper, частичное представление или другое решение для применения принципа СУХОЙ - PullRequest
2 голосов
/ 27 октября 2011

У меня есть представление только для чтения MVC3, содержащее таблицу, в которой отображаются свойства элемента.

Для многих свойств Предмета мы отслеживаем изменения, внесенные Продавцом в предмет. Так, например, поставщик может обновить свойство с именем «Color» со значения «Blue» до «Red». В этом представлении таблица перечисляет каждое свойство, отслеживаемое в строке таблицы, в столбце показаны «Старое значение» и «Новое значение». В следующем столбце отображается состояние текущего изменения (в ожидании утверждения, одобрено или отклонено). Однако для пользователей с правами администратора столбец будет содержать ссылки («Одобрить», «Отклонить» или «Сбросить в ожидании утверждения»).

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

Вот пример кода, используемого для одного свойства. Этот код повторяется для еще 10 или около того свойств.

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

    <tr id="rowId-color">
        <td>@Html.LabelFor(model => model.Color)</td>
        <td>@Html.DisplayFor(model => model.Color)</td>
        @if (Model.ChangeLog != null && Model.ChangeLog.Item("Color") != null) {
            var change = Model.ChangeLog.Item("Color");
            var changeStatus = (ItemEnumerations.ItemChangeStatuses)change.ItemChangeStatusID;
            <td>@change.OldValueDisplay</td>
            <td id="tdstatusId-@change.ItemChangeID">                                                                                
                @if (changeStatus == ItemEnumerations.ItemChangeStatuses.AwaitingApproval && User.IsInRole("TVAPMgr")) {
                                            @Ajax.ActionLink("Approve", "Approve", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Approve this change?", OnSuccess = "actionCompleted" })
                                            @Html.Raw("|")
                                            <a href="#dialog" name="reject" data-id="@change.ItemChangeID" >Reject</a>
                }
                else if ((changeStatus == ItemEnumerations.ItemChangeStatuses.Rejected || changeStatus == ItemEnumerations.ItemChangeStatuses.Approved) && User.IsInRole("TVAPMgr")) { 
                    @Ajax.ActionLink("Reset to Awaiting Approval", "Reset", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Reset this change to Awaiting Approval?", OnSuccess = "actionCompleted" })
                }
                else {
                    @changeStatus.ToDisplayString()
                }
            </td> 
            <td  id="tdreasonId-@change.ItemChangeID">@Html.DisplayFor(m => m.ChangeLog.Item(change.ItemChangeID).RejectedReason)</td>
        }
        else {
            <td colspan="3">No Change</td>
        }
    </tr>

Ответы [ 2 ]

2 голосов
/ 27 октября 2011

Это действительно больше похоже на DisplayTemplate для типа ItemChangeModel, так что вы можете просто сделать:

 <tr id="rowId-color">
    <td>@Html.LabelFor(model => model.Color)</td>
    <td>@Html.DisplayFor(model => model.Color)</td>
    @Html.DisplayFor(m => m.ChangeLog.Item("Color"))
</tr>

Для каждой ячейки ChangeLog и шаблона отображения это похоже на мини-представление с напечатанной моделью ItemChangeModel. Итак, ваш файл просмотра должен выглядеть так:

@model ItemChangeModel

@if(Model != null) {

<td>@Html.DisplayFor(m => m.OldValueDisplay)</td>
<td id="tdstatusId-@Model.ItemChangeID">

@switch((ItemEnumerations.ItemChangeStatuses) Model.ItemChangeStatusID) {

    case ItemEnumerations.ItemChangeStatuses.AwaitingApproval:
        if(User.IsInRole("TVAPMgr")) {

            @Ajax.ActionLink("Approve", "Approve", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Approve this change?", OnSuccess = "actionCompleted" })

            @Html.Raw("|")

            <a href="#dialog" name="reject" data-id="@change.ItemChangeID" >Reject</a>

        }
        break;

    case ItemEnumerations.ItemChangeStatuses.Rejected:
    case ItemEnumerations.ItemChangeStatuses.Approved:

        if(User.IsInRole("TVAPMgr")) { 
                @Ajax.ActionLink("Reset to Awaiting Approval", "Reset", new { itemChangeID = change.ItemChangeID }, new AjaxOptions { HttpMethod = "POST", Confirm = "Reset this change to Awaiting Approval?", OnSuccess = "actionCompleted" })
        } else {
                @changeStatus.ToDisplayString()
        }

        @break;
 }

  </td> 
  <td  id="tdreasonId-@change.ItemChangeID">@Html.DisplayFor(m => m.RejectedReason)          </td>
} else {
    <td colspan="3">No Change</td>
}

(Трудно кодировать в окне редактора, для этого может потребоваться некоторая очистка, но я думаю, что вы поймете идею)

Вы добавляете этот шаблон отображения (с именем файла ItemChangeModel.cshtml) в папку Views \ Shared \ DisplayTemplates, и он будет использоваться при каждом вызове DisplayFor для этого типа.

В комментариях было отмечено, что вы не можете использовать метод в DisplayFor, но вы можете изменить его на индексированное свойство:

public class ChangeLog
{
    public ItemChangeModel this[string key] { get { return Item("Color"); } }
}

Тогда используйте:

@Html.DisplayFor(m => m.ChangeLog["Color"])
1 голос
/ 27 октября 2011

Вы не показали и не объяснили, как выглядят модели вашего домена и представления, но я подозреваю, что то, что вы используете здесь, не является подходящей моделью представления для этого конкретного требования представления.Лучшей моделью представления была бы модель с списком утвержденных свойств, которые будут показаны в таблице.

В любом случае, одним из возможных подходов является написание специального помощника HTML, чтобы ваше представление выглядело так:

<tr id="rowId-color">
    @Html.DisplayFor(x => x.Color)
    @Html.ChangeLogFor(x => x.Color)
</tr>
...

и помощник может быть чем-то вроде:

public static class HtmlExtensions
{
    public static IHtmlString ChangeLogFor<TProperty>(
        this HtmlHelper<MyViewModel> html, 
        Expression<Func<MyViewModel, TProperty>> ex
    )
    {
        var model = html.ViewData.Model;
        var itemName = ((MemberExpression)ex.Body).Member.Name;
        var change = model.ChangeLog.Item(itemName);
        if (change == null)
        {
            return new HtmlString("<td colspan=\"3\">No Change</td>");
        }

        var isUserTVAPMgr = html.ViewContext.HttpContext.User.IsInRole("TVAPMgr");
        var changeStatus = (ItemChangeStatuses)change.ItemChangeStatusID;

        var sb = new StringBuilder();
        sb.AppendFormat("<td>{0}</td>", html.Encode(change.OldValueDisplay));
        sb.AppendFormat("<td id=\"tdstatusId-{0}\">", change.ItemChangeID);
        var ajax = new AjaxHelper<MyViewModel>(html.ViewContext, html.ViewDataContainer);
        if (changeStatus == ItemChangeStatuses.AwaitingApproval && isUserTVAPMgr)
        {
            sb.Append(
                ajax.ActionLink(
                    "Approve", 
                    "Approve", 
                    new { 
                        itemChangeID = change.ItemChangeID 
                    }, 
                    new AjaxOptions { 
                        HttpMethod = "POST", 
                        Confirm = "Approve this change?", 
                        OnSuccess = "actionCompleted" 
                }).ToHtmlString()
            );
            sb.Append("|");
            sb.AppendFormat("<a href=\"#dialog\" name=\"reject\" data-id=\"{0}\">Reject</a>", change.ItemChangeID);
        }
        else if ((changeStatus == ItemChangeStatuses.Rejected || changeStatus == ItemChangeStatuses.Approved) && isUserTVAPMgr)
        {
            sb.Append(
                ajax.ActionLink(
                    "Reset to Awaiting Approval", 
                    "Reset", 
                    new { 
                        itemChangeID = change.ItemChangeID 
                    }, 
                    new AjaxOptions { 
                        HttpMethod = "POST", 
                        Confirm = "Reset this change to Awaiting Approval?", 
                        OnSuccess = "actionCompleted" 
                    }
                ).ToHtmlString()
            );
        }
        else
        {
            sb.Append(changeStatus.ToDisplayString());
        }

        sb.AppendLine("</td>");
        sb.AppendFormat(
            "<td id=\"tdreasonId-{0}\">{1}</td>", 
            change.ItemChangeID, 
            html.Encode(model.ChangeLog.Item(change.ItemChangeID).RejectedReason)
        );
        return new HtmlString(sb.ToString());
    }
}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...