Динамически добавленное событие команды ImageButton не срабатывает до второго щелчка

У меня есть страница, на которой я динамически добавляю ImageButtons. Сначала я установил OnClientClick кнопок, чтобы просто показать всплывающее окно с увеличенным изображением и вернуть false для отсутствия обратной передачи.

У меня есть кнопка на странице для установки «основного изображения», поэтому при нажатии этой кнопки я устанавливаю свойство с именем _IsSettingPrimaryPhotoMode = true, вызываю функцию для воссоздания ImageButtons и при создании ImageButtons, если это свойство истинно, вместо добавления OnClientClick , я подключаю CommandEventHandler, чтобы определить, какая кнопка была нажата, прочитав CommandArgument.

Проблема в том, что обработчик событий срабатывает не при первом щелчке изображения, а только при втором щелчке и после этого. Я также переместил код с Page_Load на OnInit и загружаю ImageButtons при каждой обратной передаче.

Я сохраняю _IsSettingPrimaryPhotoMode в Session.

private bool _IsSettingPrimaryPhotoMode {
    get {
        bool result = false;

        if(Session[ConstantsWeb.Session.IS_DELETE_IMAGE_MODE] != null) {
            result = Convert.ToBoolean(Session[ConstantsWeb.Session.IS_SETTING_PRIMARY_IMAGE_MODE]);
        }

        return result;
    }
    set {
        Session[ConstantsWeb.Session.IS_SETTING_PRIMARY_IMAGE_MODE] = value;
    }
}

Страница OnInit

protected override void OnInit(EventArgs e) {
    base.OnInit(e);

        if(!IsPostBack) {
            _IsSettingPrimaryPhotoMode = false;
        }

        _LoadGalleryImages();
    }
}

Метод _LoadGalleryImages

private void _LoadGalleryImages() {
    PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();

    foreach(PhotoGalleryImage image in images) {
        ImageButton displayImage = new ImageButton();
        Panel panel = new Panel();
        panelPhotoContainer.Controls.Add(panel);
        displayImage.ImageUrl = "some URL";

        if(!_IsSettingPrimaryPhotoMode) {
            displayImage.OnClientClick = "showPopup(); return false;";
        }
        else {
            displayImage.Command += new CommandEventHandler(displayImage_Command);
            displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
            displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
        }

        panel.Controls.Add(displayImage);
    }
}

btnSetPrimaryPhoto_Click

protected void btnSetPrimaryPhoto_Click(object sender, EventArgs e) {
    // if I don't call this, duplicate controls will be added since they were added
    // from OnInit calling _LoadGalleryImages();
    panelPhotoContainer.Controls.Clear();
    _IsSettingPrimaryPhotoMode = true;
    // reload since _IsSettingPrimaryPhotoMode has now changed
    _LoadGalleryImages();
}

Что я делаю неправильно?


person Wayland Young    schedule 23.02.2012    source источник
comment
Попробуйте также добавить этот код и посмотрите, исправит ли он вашу проблему displayImage.Command -= new CommandEventHandler(displayImage_Command);   -  person MethodMan    schedule 23.02.2012
comment
Почему вы вызываете _LoadGalleryImages() при нажатии кнопки и другом событии?   -  person O.O    schedule 23.02.2012


Ответы (3)


Я предполагаю, что проблема может быть вызвана тем, что вы не установили IDs динамически созданных элементов управления. Это очень важно, так как используется в процессе запуска событий обратной отправки. Значение ID для каждого элемента управления должно быть постоянным и не меняться между обратными передачами.

Вы можете попробовать изменить свой метод _LoadGalleryImages() следующим образом:

private void _LoadGalleryImages() {
    PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();

    int imageCtrlCounter = 0;
    foreach(PhotoGalleryImage image in images) {
        ImageButton displayImage = new ImageButton() { ID = String.Format("myDisplayImage{0}", imageCtrlCounter) };
        Panel panel = new Panel();
        panelPhotoContainer.Controls.Add(panel);
        displayImage.ImageUrl = "some URL";

        if(!_IsSettingPrimaryPhotoMode) {
            displayImage.OnClientClick = "showPopup(); return false;";
        }
        else {
            displayImage.Command += new CommandEventHandler(displayImage_Command);
            displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
            displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
        }

        panel.Controls.Add(displayImage);
        imageCtrlCounter++;
    }
}
person Lukasz M    schedule 23.02.2012
comment
Проблема не в установке идентификаторов. - person Wayland Young; 24.02.2012
comment
Ну, это было частью проблемы, но решение @swannee было полным ответом, поэтому я отметил его ответ, но щелкнул, что ваш был полезен. - person Wayland Young; 24.02.2012
comment
О, я вижу, я не вижу голосов за мой ответ (однако может быть некоторая задержка). В любом случае, хорошо, что вы это исправили :). - person Lukasz M; 24.02.2012
comment
@Lucas: я бы дал тебе удар, но я выложился на весь день... дам тебе завтра. - person swannee; 24.02.2012
comment
@swannee: Спасибо, поскольку то, что вы упомянули, помогло решить проблему, я также проголосовал за вас :). - person Lukasz M; 25.02.2012

Это должно быть что-то, связанное с начальным подключением события, потому что проблема возникает только в первый раз. Что отличается от того времени, так это то, что _LoadGalleryImages вызывается дважды (один раз в инициализации и один раз в обработчике события нажатия кнопки), поэтому я думаю, что что-то там не очищается, когда вы очищаете панель контейнера и снова вызываете _LoadGalleryImages при нажатии кнопки обработчик.

Почему бы не попробовать эту альтернативу: вызывать LoadImageGalleries только один раз за цикл страницы (в инициализации).

Вместо того, чтобы очищать элементы управления и снова вызывать LoadGalleryImages в той же обратной передаче (в событии нажатия кнопки), при нажатии кнопки вызывается метод, который перебирает элементы управления изображением, которые вы уже создали при вызове LoadGalleryImages, и корректирует их:

1) Удалите onclientclick (очистите его).

2) Прикрепить событие.

person swannee    schedule 23.02.2012
comment
Я не думаю, что это сработает, поскольку элементы управления добавляются динамически. Я попытался перебрать элементы управления страницей, и они не существуют, поскольку они были добавлены в if(!IsPostBack) {} в OnInit, но их нет после нажатия кнопки страницы. Я думаю, что необходимо всегда вызывать _LoadGalleryImages в OnInit, чтобы DOM и состояние страницы каждый раз были одинаковыми. Проблема была в том, что я не добавлял идентификаторы в элементы управления. - person Wayland Young; 24.02.2012
comment
Не уверен, что вы поняли мой ответ, я не имел в виду вызов только один раз... Я имел в виду вызов только один раз за цикл страницы (в инициализации). Но пока исправление работает.... Отлично! - person swannee; 24.02.2012
comment
Теперь я понимаю, что вы имеете в виду. Смотрите мое решение в ответе. - person Wayland Young; 24.02.2012
comment
Я не знал, что у меня недостаточно репутации, чтобы ответить на свой вопрос, не дожидаясь 8 часов. Смотрите мое решение позже. - person Wayland Young; 24.02.2012
comment
Забавно, ок, подождем ответа. - person swannee; 24.02.2012
comment
Взгляните на мое решение ниже и посмотрите, что вы думаете. - person Wayland Young; 24.02.2012

@swannee
На самом деле, ваш метод действительно сработал после того, как я подумал об этом. Теперь я вызываю _LoadGalleryImages для каждого OnInit. Я понимаю, что это много повторяющегося кода, который можно объединить.

Новый _LoadGalleryImages

private void _LoadGalleryImages() {
    PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();

    foreach(PhotoGalleryImage image in images) {
        Panel panel = new Panel();
        panelPhotoContainer.Controls.Add(panel);

        ImageButton displayImage = new ImageButton();
        panel.Controls.Add(displayImage);
        displayImage.ID = string.Format("ImageButton{0}", image.PhotoGalleryImageId);
        displayImage.ImageUrl = "Some URL";
        displayImage.AlternateText = displayImage.ToolTip = image.ImageName;

        if(!_IsSettingPrimaryPhotoMode) {
            displayImage.OnClientClick = "showPopup(); return false;";
        }
        else {
            // handles the image button command wireup
            displayImage.Command += new CommandEventHandler(displayImage_Command);
            displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
        }
    }
}



Я добавил новый метод, как вы предложили, чтобы найти элементы управления, поскольку они уже были созданы в OnInit, и мне просто нужно найти их после нажатия кнопки и очистить OnClientClick.

private void _LoadSelectPrimaryImages() {
    PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();

    foreach(PhotoGalleryImage image in images) {
        Control control = panelPhotoContainer.FindControl(string.Format("ImageButton{0}", image.PhotoGalleryImageId));

        if(control != null) {
            ImageButton displayImage = (ImageButton)control;
            displayImage.OnClientClick = "";
        }
    }
}



У меня также есть кнопка отмены, чтобы вернуть кнопки изображения в то состояние, в котором они были до отображения всплывающего окна.

private void _ResetGalleryImages() {
    PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages(_photoGalleryId, false, true);

    foreach(PhotoGalleryImage image in images) {
        Control control = panelPhotoContainer.FindControl(string.Format("ImageButton{0}", image.PhotoGalleryImageId));

        if(control != null) {
            ImageButton displayImage = (ImageButton)control;
            displayImage.ImageUrl = "Original URL";
            displayImage.OnClientClick = "showPopup(); return false;";
        }
    }
}



и две кнопки страницы

protected void btnSetPrimaryPhoto_Click(object sender, EventArgs e) {
    _IsSettingPrimaryPhotoMode = true;
    _LoadSelectPrimaryImages();
}



protected void btnCancelSetPrimaryPhoto_Click(object sender, EventArgs e) {
    _IsSettingPrimaryPhotoMode = false;
    _ResetGalleryImages();
}



Кто-то сказал в ответе ранее... похоже, что ответ был удален... чтобы очистить элементы управления в _LoadGalleryImages, такие как:

private void _LoadGalleryImages() {
    panelPhotoContainer.Controls.Clear();
    PhotoGalleryImageCollection images = PhotoGalleryImages.GetPhotoGalleryImages();

    foreach(PhotoGalleryImage image in images) {
        ImageButton displayImage = new ImageButton();
        Panel panel = new Panel();
        panelPhotoContainer.Controls.Add(panel);
        displayImage.ImageUrl = "some URL";

        if(!_IsSettingPrimaryPhotoMode) {
            displayImage.OnClientClick = "showPopup(); return false;";
        }
        else {
            displayImage.Command += new CommandEventHandler(displayImage_Command);
            displayImage.CommandName = "ImageButton" + image.PhotoGalleryImageId.ToString();
            displayImage.CommandArgument = image.PhotoGalleryImageId.ToString();
        }

        panel.Controls.Add(displayImage);
    }
}



который также работает, но я думаю, что он может быть более неэффективным, чем ваш метод, @swannee. Спасибо!

person Wayland Young    schedule 24.02.2012