我有一个MVC3只读视图,其中包含一个显示项目属性的表。
对于项目的许多属性,我们会跟踪供应商对项目所做的更改。因此,例如,供应商可以将名为“Color”的属性从“Blue”值更新为“Red”。在此视图中,表格列出了表格行中跟踪的每个属性,其中一列显示“旧值”和“新值”。下一列显示当前更改的状态(等待批准,已批准或已拒绝)。但是,对于管理员用户,该列将包含链接(“批准”,“拒绝”或“重置为等待批准”)。
我的标记和Razor代码非常重复且失控。我想为此创建一个HTMLHelper,或者可能是部分视图,我可以使用它将所有代码移入,然后将其用于每个Item属性。
以下是一个Property使用的代码示例。对于另外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>
答案 0 :(得分:2)
这听起来更像是ItemChangeModel
类型的DisplayTemplate,你可以这样做:
<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 :(得分:1)
您尚未显示或解释您的域和视图模型的外观,但我怀疑您在此处使用的内容不适合视图的特定要求。一个更好的视图模型将是一个具有要批准的属性列表的模型,该模型将显示在表中。
无论如何,一种可能的方法是编写自定义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());
}
}
更好的方法是重新调整视图模型以适应此视图的要求,并简单地使用显示模板。