我有一个视图,其中包含通过局部视图渲染的项目列表。
我希望能够在局部视图中为整个页面仅添加一次javascript脚本。我读到可以在所有(部分)视图之间使用Context.Items
共享数据(如布尔ScriptAlreadyIncluded
)。
但是我可以依靠吗?还是我应该使用其他东西?
我当前的代码(最相关的局部视图是ITypedModel.cshtml和AFieldFormula_DirectFieldFormula.cshtm)
Index.cshtml
@model IEnumerable<MygLogWeb.Classes.MemberField>
@{
Layout = "~/Views/Shared/_Layout.cshtml";
var uid = Guid.NewGuid().ToString();
}
@using (Html.BeginForm("Index", "MemberField", FormMethod.Post, new { id = uid }))
{
@Html.AntiForgeryToken()
<table class="table none">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.IsSystem)
</th>
<th>
@Html.DisplayNameFor(model => model.IsVirtual)
</th>
<th>
@Html.DisplayNameFor(model => model.Name)
</th>
<th>
@Html.DisplayNameFor(model => model.Formula)
</th>
<th></th>
</tr>
</thead>
<tbody>
@Html.EditorFor(model => model)
</tbody>
<tfoot>
<tr>
<td colspan="5">
<input type="button" value="@Resources.Common.Buttons.add" />
</td>
</tr>
</tfoot>
</table>
<input type="submit" value="@Resources.Common.Buttons.save"/>
}
<script type="text/javascript">
new TableEdit("@uid");
</script>
EditorTemplates/MemberField.cshtml
@model MygLogWeb.Classes.MemberField
<tr>
<td>
@Html.DisplayFor(model => model.IsSystem)
@Html.HiddenFor(model => model.IsSystem)
</td>
<td>
@Html.DisplayFor(model => model.IsVirtual)
@Html.HiddenFor(model => model.IsVirtual)
</td>
<td>
@if (Model.IsSystem)
{
@Html.DisplayFor(model => model.Name)
@Html.HiddenFor(model => model.Name)
}
else
{
@Html.TextBoxFor(model => model.Name, new { data_focus = "true" })
@Html.ValidationMessageFor(model => model.Name)
}
</td>
<td>
@Html.EditorFor(model => model.Formula, "ITypedModel")
</td>
<td>
@if (!Model.IsSystem)
{
<input type="button" value="@Resources.Common.Buttons.delete" data-code="delete" />
}
</td>
</tr>
EditorTemplates/ITypedModel.cshtml
...
@foreach (var item in items)
{
<span data-refered-type="@item.Item.Value">
@if (item.Type.IsSubclassOf(typeof(AFieldFormula)))
{
var newModel = item.Item.Selected ? Model : Activator.CreateInstance(item.Type);
@Html.Partial("~/Views/MemberField/EditorTemplates/AFieldFormula_" + item.Type.Name + ".cshtml", newModel)
}
</span>
}
EditorTemplates/AFieldFormula_ConstantFormula.cshtml
@model MygLogWeb.Classes.ConstantFormula
<b>ConstantFormula</b>
@Html.EditorFor(model => model.Constant)
@Html.ValidationMessageFor(model => model.Constant)
EditorTemplates/AFieldFormula_DirectFieldFormula.cshtml
@model MygLogWeb.Classes.DirectFieldFormula
...Build a JSON dictionnary...
<b>DirectFieldFormula</b>
@Html.EditorFor(model => model.Field)
@Html.ValidationMessageFor(model => model.Field)
...Some controls using the JSON dictionnary...
每个AFieldFormula_DirectFieldFormula.cshtml视图的字典都是相同的,所以我只想对每个网页进行计算和显示一次。
Context.Items(线程)安全吗?
否,因为HttpContext在文档中不是线程安全的
此类型的任何公共静态(在Visual Basic中为共享)成员都是线程安全的。不保证任何实例成员都是线程安全的。
如果要一次渲染它,则可以在第一个渲染中的页面中添加一个隐藏字段,并在后续渲染中检查该字段是否存在。
根据您的评论,您应该能够使用ViewBag
来维护各个局部视图的状态,并确保脚本仅被渲染一次
ITypedModel.cshtml
...
@foreach (var item in items)
{
<span data-refered-type="@item.Item.Value">
@if (item.Type.IsSubclassOf(typeof(AFieldFormula)))
{
var newModel = item.Item.Selected ? Model : Activator.CreateInstance(item.Type);
@Html.Partial("~/Views/MemberField/EditorTemplates/AFieldFormula_" + item.Type.Name + ".cshtml", newModel, new ViewDataDictionary { { "vb", ViewBag }})
}
</span>
}
AFieldFormula_DirectFieldFormula.cshtml
@model MygLogWeb.Classes.DirectFieldFormula
@{ var vb = ((dynamic)ViewData["vb"]); }
@if (!vb.ScriptAlreadyIncluded)
{
...Build a JSON dictionnary...
}
<b>DirectFieldFormula</b>
@Html.EditorFor(model => model.Field)
@Html.ValidationMessageFor(model => model.Field)
@if (!vb.ScriptAlreadyIncluded)
{
...Some controls using the JSON dictionnary...
}
@if (!vb.ScriptAlreadyIncluded)
{
@{ vb.ScriptAlreadyIncluded = true; } // set the flag
}
这将在首次调用RenderPartial("AFieldFormula_DirectFieldFormula")
时呈现脚本,然后将ViewBag.ScriptAlreadyIncluded
属性设置为true
。然后,在后续渲染中(在传递ViewBag
时),此属性将跳过JS内容,因为已经设置了ScriptAlreadyIncluded
。
Context.Items(线程)安全吗?
但是它一定是吗?如果您不执行任何异步处理,则您的请求将全部在同一线程上执行,因此线程安全性不是问题。
并且Context.Items旨在在请求处理管道的不同部分之间共享对象。
基于@詹姆斯的想法和this post
我可以只使用:ViewContext.Controller.ViewBag
,因为我整个页面只有一个Controller(我在那里不使用ChildActions。)>
它给出:
@model MygLogWeb.Classes.DirectFieldFormula
@{
var GlobalViewBag = ViewContext.Controller.ViewBag;
if (GlobalViewBag.DirectFieldFormula_ScriptAlreadyIncluded as bool? != true)
{
<script type="text/javascript">
// ...
</script>
}
GlobalViewBag.DirectFieldFormula_ScriptAlreadyIncluded = true;
}
...
所以,这是一个古老的问题,但是我在尝试解决最近的问题时发现了它。