c# - 在 ASP.NET MVC 3 View 层次结构之间传递的数据

标签 c# asp.net asp.net-mvc asp.net-mvc-3 razor

动机

我希望能够在 Javascript 中构建一个树状对象层次结构,它对应于页面上的 ASP.NET MVC 3 Razor View 。计划是在 Razor View 和定义其逻辑的 Javascript 文件之间建立一对一的对应关系(以接受一些初始化参数的构造函数的形式)。简单的例子可能是这样的:

  • _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);

当然,所有这些代码都应该根据从部分 View 收集的元数据在根(布局) View 的上下文中自动构建。 View 提供的元数据包含初始化其 Javascript 对象和要加载的 Javascript 文件所需的选项。

问题

与 WebForms 不同,MVC View 没有任何我所知道的自然层次结构,并且在 View 及其部分(子) View 之间传递信息似乎相当棘手。如果使用像 Html.Action 这样的助手在 View 中,“ subview ”的整个处理过程都是独立发生的,因此它们甚至不共享 Page。目的。我需要的是某种中心位置, View 可以在渲染时存放它们的元数据,以便可以在布局 View 中使用它来组合和输出完整的脚本。

解决方案?

我能想到的一种方法是使用 HttpContext.Current.Items临时存储 View 元数据对象的集合。所有 View 都会将元数据存放在那里,而布局 View 会使用它。执行顺序似乎符合我的预期,但我仍然无法重建 View 的树层次结构。为了能够做到这一点,我需要使用一个堆栈,其中 View 将在其渲染开始时注册并在结束时注销,以便可以在顶部找到父 View 。

  1. 有没有办法在我可以放置此逻辑的地方设置一些渲染前/渲染后的 Hook ?
  2. 这首先是个好主意吗?
  3. 是否有我没有看到的完全不同的解决方案?

最佳答案

您可以编写自定义 View 引擎:

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);
    }
}

您将在 Application_Start 中注册:

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(new MyViewEngine());

现在您可以编写一个自定义 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
        ...
    }
}

在你的 _Layout 的最后:

    ...
    <script type="text/javascript">
        @Html.BuildTree()
    </script>
</body>

关于c# - 在 ASP.NET MVC 3 View 层次结构之间传递的数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8962311/

相关文章:

c# - 使用 Linq 从表中提取数据

c# - c# 中的 GetEnumerator() 是否返回副本或迭代原始源?

c# - 计算驱动器上的文件数

c# - 要区分的 KeyValuePair 列表

c# - 在 asp.net MVC6 View 中删除 if 语句的最佳方法

c# - ASP.NET 3.5 MVC1 - 用户随机未经身份验证/需要重新登录

.net - 学习 Asp.Net WebForms 或 Asp.Net MVC

c# - TPL 数据流 : Persist previous data

c# - htmlAttributes 未与我的扩展中的标签生成器合并

javascript - ClientScript 在 C# 类上无法正常工作