C# ASP.NET MVC 3视图层次结构之间的数据传递 动机
我希望能够在Javascript中建立一个树状的对象层次结构,它对应于页面上的ASP.NET MVC 3 Razor视图。计划是在Razor视图和定义其逻辑的Javascript文件之间建立一对一的对应关系(以接受一些初始化参数的构造函数的形式)。简单的例子如下所示:C# ASP.NET MVC 3视图层次结构之间的数据传递 动机,c#,asp.net,asp.net-mvc,asp.net-mvc-3,razor,C#,Asp.net,Asp.net Mvc,Asp.net Mvc 3,Razor,我希望能够在Javascript中建立一个树状的对象层次结构,它对应于页面上的ASP.NET MVC 3 Razor视图。计划是在Razor视图和定义其逻辑的Javascript文件之间建立一对一的对应关系(以接受一些初始化参数的构造函数的形式)。简单的例子如下所示: \u Layout.cshtml Global.js SplitterPane.cshtml SplitterPane.js Grid.cshtml Grid.js Tree.cshtml Tree.js 我将使用构造
\u Layout.cshtml Global.js
SplitterPane.cshtml SplitterPane.js
Grid.cshtml Grid.js
Tree.cshtml Tree.js
var page = new Global(global_options);
var splitter = new SplitterPane(splitter_options);
var grid = new Grid(grid_options);
var tree = new Tree(tree_options);
page.addChild(splitter);
splitter.addChild(grid);
splitter.addChild(tree);
当然,所有这些代码都应该在根(布局)视图的上下文中根据从局部视图收集的元数据自动构造。视图提供的元数据包含初始化其Javascript对象和要加载的Javascript文件所需的选项
问题
与WebForms不同,MVC视图没有我所知道的任何自然层次结构,在视图及其部分(子)视图之间传递信息似乎相当棘手。如果在视图中使用像Html.Action
这样的帮助程序,“子视图”的整个处理过程是独立进行的,因此它们甚至不共享页面
对象。我需要的是某种中心位置,视图可以在呈现时存放元数据,以便在布局视图中使用元数据来组合和输出完整的脚本
解决方案
我能想到的一种方法是使用HttpContext.Current.Items
临时存储视图元数据对象的集合。所有视图都将元数据存放在那里,布局视图将使用它。执行顺序似乎符合我的期望,但是我仍然无法重建视图的树层次结构。要做到这一点,我需要使用一个堆栈,其中视图将在渲染开始时注册,在渲染结束时取消注册,以便可以在顶部找到父视图
如果只想将视图与Javascript文件关联,请在layout.cshtml中定义一个部分(在关闭body标记之前): 然后在页面和视图中:
@section scripts {
<script type="text/javascript" src="path to script"></script> }
@节脚本{
}
但是,一旦您开始使用局部视图,这将不起作用。为了处理局部视图,我使用了自定义Html扩展@Html.RenderResource(“{sectionname},~/{path to resource}”)您可以编写一个自定义视图引擎:
public class MyViewEngine : RazorViewEngine
{
private class MyRazorView : RazorView
{
public MyRazorView(ControllerContext controllerContext, string viewPath, string layoutPath, bool runViewStartPages, IEnumerable<string> viewStartFileExtensions, IViewPageActivator viewPageActivator)
: base(controllerContext, viewPath, layoutPath, runViewStartPages, viewStartFileExtensions)
{
}
protected override void RenderView(ViewContext viewContext, System.IO.TextWriter writer, object instance)
{
var stack = viewContext.HttpContext.Items["stack"] as Stack<string>;
if (stack == null)
{
stack = new Stack<string>();
viewContext.HttpContext.Items["stack"] = stack;
}
// depending on the required logic you could
// use a stack of some model and push some additional
// information about the view (see below)
stack.Push(this.ViewPath);
base.RenderView(viewContext, writer, instance);
}
}
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
{
return new MyRazorView(controllerContext, viewPath, masterPath, true, base.FileExtensions, base.ViewPageActivator);
}
protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
{
return new MyRazorView(controllerContext, partialPath, null, false, base.FileExtensions, base.ViewPageActivator);
}
}
现在,您可以编写一个自定义HTML帮助程序,它将选择存储在HttpContext中的堆栈并执行一些有用的操作:
public static class HtmlExtensions
{
public static IHtmlString BuildTree(this HtmlHelper htmlHelper)
{
var stack = htmlHelper.ViewContext.HttpContext.Items["stack"] as Stack<string>;
if (stack == null)
{
return MvcHtmlString.Empty;
}
// TODO: your custom logic to build the tree
...
}
}
public静态类
{
公共静态IHtmlString构建树(此HtmlHelper HtmlHelper)
{
var stack=htmlHelper.ViewContext.HttpContext.Items[“stack”]作为堆栈;
if(stack==null)
{
返回MvcHtmlString.Empty;
}
//TODO:构建树的自定义逻辑
...
}
}
在您的_布局的末尾:
...
<script type="text/javascript">
@Html.BuildTree()
</script>
</body>
。。。
@Html.BuildTree()
正如您所说,分区不适用于局部视图。您提到的扩展使用了类似于我提出的解决方案的方法,因此我提出的三个问题仍然适用:)这是一个非常好和彻底的解决方案!!谢谢,听起来很酷..重建树唯一缺少的是父视图和子视图之间的链接。我我可以通过保持一个平行的“父”堆栈来做到这一点,在调用base.RenderView之前推送一个项,然后在调用之后弹出它。这应该可以,对吧?
public static class HtmlExtensions
{
public static IHtmlString BuildTree(this HtmlHelper htmlHelper)
{
var stack = htmlHelper.ViewContext.HttpContext.Items["stack"] as Stack<string>;
if (stack == null)
{
return MvcHtmlString.Empty;
}
// TODO: your custom logic to build the tree
...
}
}
...
<script type="text/javascript">
@Html.BuildTree()
</script>
</body>