Передача данных между иерархией представления ASP.NET MVC 3 - PullRequest
4 голосов
/ 22 января 2012

Мотивация

Я хочу иметь возможность создавать древовидную иерархию объектов в Javascript, соответствующую представлениям ASP.NET MVC 3 Razor на странице.План состоит в том, чтобы иметь взаимно-однозначное соответствие между представлением Razor и файлом 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);

Весь этот код, конечно, должен автоматически создаваться в контекстекорневого представления (макета) из метаданных, собранных из частичных представлений.Метаданные, предоставляемые представлением, содержат параметры, необходимые для инициализации его объекта Javascript и загружаемых файлов Javascript.

Проблема

В отличие от WebForms, представления MVC не имеют никакой естественной иерархии, о которой я мог бы знать, иПередача информации между представлением и его частичными (под) представлениями выглядит довольно сложно.В случае использования помощников, таких как Html.Action в представлении, вся обработка «подпредставления» происходит независимо, поэтому они даже не разделяют объект Page.Что мне нужно, так это какое-то центральное место, где представления могут размещать свои метаданные по мере их отображения, чтобы их можно было использовать в представлении макета для объединения и вывода всего сценария.

Решение?

Один из способов, который я мог придумать, - это использовать HttpContext.Current.Items для временного хранения коллекции объектов метаданных представления.Все представления будут хранить метаданные там, и представление макета будет использовать его.Кажется, порядок выполнения соответствует моим ожиданиям, однако я все еще не могу восстановить древовидную иерархию представлений.Чтобы сделать это, мне нужно было бы использовать стек, где представление регистрировалось бы в начале своего рендеринга и отменяло регистрацию в конце, чтобы родительский элемент находился вверху.

  1. Есть ли способ иметь некоторые хуки до / после рендеринга, куда я мог бы поместить эту логику?
  2. Это вообще хорошая идея с самого начала?
  3. Есть ли совсем другое решение, которого я не вижу?

Ответы [ 2 ]

2 голосов
/ 23 января 2012

Вы можете написать собственный движок представления:

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>
0 голосов
/ 22 января 2012

Если вы просто хотите связать представление с файлом Javascript, определите раздел в layout.cshtml (до закрытия тега body):

@RenderSection("scripts", false")

Затем в ваших страницах и представлениях:

@section scripts {
<script type="text/javascript" src="path to script"></script> }

Однако это не сработает, когда вы перейдете к частичным видам.Для обработки частичных представлений я использовал собственное расширение HTML.@ Html.RenderResource ("{sectionname}," ~ / {путь к ресурсу} ")

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