Динамические данные ASP.NET: таблица больше не отображается после вставки данных, если доступ к FormView.Controls осуществляется по событию Page.Initialized - PullRequest
4 голосов
/ 15 июня 2011

В последнее время я получил сообщение об ошибке для Ninject.Web, что он не работает должным образом вместе с динамическими данными ASP.NET.Проблема в том, что при обратной передаче (например, при вставке, удалении, редактировании записи) таблица больше не отображается.

Некоторые отладки показали, что проблема вызвана IHttpModule, который рекурсивно перебирает все элементы управления страницы после его инициализации.Как только этот модуль получает доступ к свойству Controls, получает доступ к FormView или GridView, возникает проблема.Если этот тип элементов управления пропущен, все в порядке.В следующем коде показан модуль:

public class NinjectHttpModule : DisposableObject, IHttpModule
{
    private HttpApplication httpApplication;

    public void Init(HttpApplication context)
    {
        this.httpApplication = context;
        this.httpApplication.PreRequestHandlerExecute += this.OnPreRequestHandlerExecute;
    }

    private static void InjectUserControls(Control parent)
    {
        if (parent == null)
        {
            return;
        }

        foreach (Control control in parent.Controls)
        {
            if (control is UserControl)
            {
                // KernelContainer.Inject(control); This is irrelevant for the question.
            }

            InjectUserControls(control);
        }
    }

    private void OnPreRequestHandlerExecute(object sender, EventArgs e)
    {
        var page = this.httpApplication.Context.CurrentHandler as Page;

        if (page == null)
        {
            return;
        }

        KernelContainer.Inject(page);
        page.InitComplete += (src, args) => InjectUserControls(page);
    }
}

Если этот код изменяется так, что итерация дочерних элементов управления DataBoundControls откладывается до события DataBound, все в порядке.В следующем фрагменте кода показано:

    private static void InjectUserControls(Control parent, bool skipDataBoundControls)
    {
        if (parent == null)
        {
            return;
        }

        if (skipDataBoundControls)
        {
            var dataBoundControl = parent as DataBoundControl;
            if (dataBoundControl != null)
            {
                dataBoundControl.DataBound += InjectDataBoundControl;
                return;
            }                
        }

        foreach (Control control in parent.Controls)
        {
            if (control is UserControl)
            {
                KernelContainer.Inject(control);
            }

            InjectUserControls(control, skipDataBoundControls);
        }
    }

    private static void InjectDataBoundControl(object sender, EventArgs e)
    {
        var dataBoundControl = sender as DataBoundControl;
        if (dataBoundControl != null)
        {
            dataBoundControl.DataBound -= InjectDataBoundControl;
            InjectUserControls(dataBoundControl, false);
        }
    }

Поскольку я совершенно не знаком с System.Web.DynamicData, я хотел бы узнать некоторые вещи, чтобы лучше понять, как исправить эту ошибку:

  • Почему возникает эта проблема?Я имею в виду, что это только простой доступ для чтения к свойству Controls.
  • Какие побочные эффекты могут иметь вышеуказанные изменения?
  • Достаточно ли еще рано вводить элементы управления после события привязки данных?
  • Считаете ли вы, что это корректное исправление ошибки для этой проблемы?

1 Ответ

2 голосов
/ 19 июня 2011

Конечно, загадочное поведение, как это иногда бывает в WebForms со многими фазами выполнения.

Несмотря на то, что это просто простой доступ для чтения к свойству Controls, это свойство может действительно выполнить большую работу для возвратаребенок контролирует.В частности, он не может вернуть дочерние элементы управления, если они не были созданы, и это создание обычно не происходит до более позднего этапа жизненного цикла страницы.Таким образом, получая доступ к нему в InitComplete, дети в конечном итоге создаются преждевременно, до того, как произойдут некоторые важные подключения к динамическим данным, в результате чего некоторые элементы управления будут отсутствовать.Да, я понимаю, что поведение конечного результата, кажется, не имеет большого смысла, поэтому некоторые люди предпочитают прямолинейность MVC:)

В качестве альтернативного возможного обходного пути, не могли бы вы попробовать перенести инъекцию из InitComplete в PreLoad?например,

page.PreLoad += (src, args) => InjectUserControls(page);

Я почти уверен, что это решит проблему, хотя я менее уверен, вызовет ли это проблемы с вашей KernelContainer.Inject логикой.Попробуйте, так как это проще, чем ваш обходной путь.

Если это не сработает, я думаю, что ваш обходной путь в порядке, так как он задерживает перечисление до тех пор, пока не будут созданы дочерние элементы.Что касается '. Достаточно ли еще рано вводить элементы управления после события привязки данных ', я думаю, что это зависит от того, что именно делает KernelContainer.Inject, и от того, какие ожидания он ожидает от состояния элемента управления.

...