Почему мои дочерние элементы управления не были инициализированы во время прикрепления события? - PullRequest
2 голосов
/ 05 августа 2009

У меня есть страница и пользовательский элемент управления & mdash; мы будем называть их Detail.aspx и Selector.ascx.

Допустим, на странице показаны подробности отдельных записей в базе данных. Пользовательский элемент управления в основном состоит из элемента управления DropDownList и некоторого связанного HTML. DropDownList отображает список других записей для переключения в любое время.

Когда DropDownList запускает событие SelectedIndexChanged, я бы хотел, чтобы родительская страница, в данном случае Detail.aspx, обрабатывала его. В конце концов, ему нужно знать, что было выбрано, чтобы он мог соответствующим образом изменить URL-адрес и отображаемые данные и т. Д.

Чтобы сделать это, я сделал то, что обычно делаю, что также говорит главный ответ в этом вопросе StackOverflow :

public event EventHandler DropDownSelectedIndexChanged
{
    add
    {
        MyDropDownList.SelectedIndexChanged += value;
    }
    remove
    {
        MyDropDownList.SelectedIndexChanged -= value;
    }
}

Приведенный выше код появляется в файле кода Selector.ascx.cs.

В результате на Detail.aspx я могу использовать его так:

<cc1:RecordSelector ID="RecordSelector1" runat="server"
OnDropDownSelectedIndexChanged="RecordSelector1_DropDownSelectedIndexChanged" />

Пока ничего необычного или удивительного.

Вот моя проблема:

Это вызывает NullReferenceException, когда браузер нажимает Detail.aspx.

Отладка проблемы показывает, что при первом обращении к странице публичное событие, которое я показывал выше, пытается добавить событие, но MyDropDownList имеет значение null, что вызывает исключение. Из того, что я могу сказать, события добавляются (или пытались быть добавленными) до события Load пользовательского элемента управления Selector и, следовательно, также до события LoadDownList.

Любопытно, если я опущу атрибут OnDropDownSelectedIndexChanged в Detail.aspx и вместо этого добавлю следующее в событие Page_Load в Detail.aspx.cs:

protected void Page_Load(object sender, EventArgs e)
{
    RecordSelector1.DropDownSelectedIndexChanged += new EventHandler(RecordSelector1_DropDownSelectedIndexChanged);
}

Работает точно так, как ожидалось. К событиям прилагаются и обрабатываются просто отлично. Нет проблем.

Но это означает несколько плохих вещей:

  1. Я должен помнить, что не следует использовать конструктор для добавления указанного события в мой пользовательский элемент управления
  2. Я должен помнить, чтобы не добавлять событие через атрибуты при работе в режиме просмотра исходного кода
  3. Хуже всего то, что как автор элемента управления мне нужно убедиться, что все остальные, использующие мой элемент управления, знают 1 и 2

Так что я делаю не так? Каждый пример, который я видел до сих пор, показывает аналогичное использование выставления событий дочерних элементов управления через пользовательский элемент управления.

1 Ответ

1 голос
/ 05 августа 2009

Причина, по которой это работает:

protected void Page_Load(object sender, EventArgs e)
{
    RecordSelector1.DropDownSelectedIndexChanged 
        += new EventHandler(RecordSelector1_DropDownSelectedIndexChanged);
}

и это не так:

<cc1:RecordSelector ID="RecordSelector1" runat="server"
OnDropDownSelectedIndexChanged="RecordSelector1_DropDownSelectedIndexChanged" />

потому, что первый добавляет обработчик после , когда элемент управления инициализирован (через Init страницы). Второй пример анализируется намного раньше, и поэтому страница пытается добавить обработчик до инициализации элемента управления.

Из-за характера жизненного цикла страницы, я думаю, вам, возможно, придется смириться с добавлением обработчика событий в коде. Не будет никакого способа добавить обработчик до инициализации элемента управления, потому что этот элемент управления всегда будет null до инициализации.

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