Модальная панель не появляется при вызове кнопкой внутри ячейки сетки

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

В контексте: у меня есть строка данных со строковым полем, которое может содержать простой текст или изображение в кодировке base 64, поэтому я использую настраиваемый шаблон, чтобы определить, когда показывать необработанный контент или кнопку «Просмотреть изображение». Это изображение будет открыто на модальной панели, которая должна подниматься по нажатию кнопки.

Это панель, которую я создал как элемент управления (ascx):

<asp:Panel ID="pnlModalOverlay" runat="server" Visible="true" CssClass="Overlay">
    <asp:Panel ID="pnlModalMainContent" runat="server" Visible="true" CssClass="ModalWindow">
        <div class="WindowTitle">
            <asp:Label ID="lbTitle" runat="server" />
        </div>
        <div class="WindowBody">
            <asp:Panel ID="pnlContent" runat="server" Visible="true">
                <asp:Image ID="imgContent" runat="server" CssClass="ImageView" />
            </asp:Panel>
            <div class="Button">
                <asp:Button ID="btnOk" runat="server" class="btn btn-default " Text="Close" OnClientClick="loadingPanel.Show();" />
            </div>
        </div>
    </asp:Panel>
</asp:Panel>

А это страница и ASPxGridView, где я хочу это использовать:

<asp:UpdatePanel ID="UpdatePanel1" runat="server" UpdateMode="Conditional" ChildrenAsTriggers="true">
    <ContentTemplate>
        <div style="margin-top: 12px;">
            <asp:Button type="button" ID="btnShowImage" AutoPostBack="true" class="btn btn-default navbar-right" Text="Show Image"
                runat="server" Style="margin-left: 5px;" OnClientClick="loadingGridPanel.Show();" />
        </div> 

        <!-- Some data filter controls  -->

        <MyWorkspace:AlertModal ID="alertModal" runat="server" Visible="false" />
        <MyWorkspace:ImageModal ID="imageModal" runat="server" Visible="false" />

    </ContentTemplate>
    <Triggers>
        <asp:AsyncPostBackTrigger ControlID="mainGrid" />
    </Triggers>
</asp:UpdatePanel>

<MyWorkspace:GridViewWrapper ID="mainGrid" runat="server" Visible="true" />

Компонент кода:

public partial class MyPage : System.Web.UI.Page
{
    protected override void OnInit(EventArgs e)
    {
        base.OnInit(e);

        btnShowImage.Click += new EventHandler(ShowImage); // This call works fine
    }

    protected void Page_Load(object sender, EventArgs e)
    {
        try
        {
            if (!IsPostBack)
            {
                mainGrid.CanEditItems = true;

                mainGrid.CustomTemplates.Add(new CustomColumnTemplate { columnName = "Id", template = new LinkColumn(CreateParentLink, "Go to parent") });
                mainGrid.CustomTemplates.Add(new CustomColumnTemplate { columnName = "Value", template = new ButtonColumn(ShowImage, "View Image") }); // This one doesn't works
            }
        }
        catch (Exception ex)
        {
            modalAlerta.Show("Page_Load", ex.Message, false, false, "");
        }
    }

    void ShowImage()
    {
        modalImagem.Show(); // Set Modal's Visible property to True
        // UpdatePanel1.Update(); <-- Tryin' force it to work with no success
    }

}

Создание шаблона ButtonColumn:

public class ButtonColumn : System.Web.UI.ITemplate
{
    private Action action;
    private string controlId;
    private string tooltip;

    public ButtonColumn(Action onClick, string toolTip)
    {
        this.action = onClick;
        this.controlId= "btnShowImage";
        this.tooltip = toolTip;
    }

    public void InstantiateIn(System.Web.UI.Control container)
    {
        GridViewDataItemTemplateContainer gridContainer = (GridViewDataItemTemplateContainer)container;

        if (System.Text.RegularExpressions.Regex.IsMatch(gridContainer.Text, "^([A-Za-z0-9+/]{4})*([A-Za-z0-9+/]{4}|[A-Za-z0-9+/]{3}=|[A-Za-z0-9+/]{2}==)$"))
        {
            ImageButton button = new ImageButton();
            button.ID = idControle;
            button.ImageUrl = "/Images/html5_badge_64.png";
            button.Width = 20;
            button.Height = 20;
            button.ToolTip = tooltip;

            button.Click += (s, a) =>
            {
                if (onClick != null)
                    onClick();
            };

            container.Controls.Add(button);
        }
        else
        {
            Label label = new Label()
            {
                Text = gridContainer.Text,
                ToolTip = tooltip
            };
            container.Controls.Add(label);
        }
    }
}

Вызов метода по нажатию кнопки btnShowImage работает нормально. Но когда я делаю тот же вызов одной кнопкой ImageButton (или кнопкой) внутри сетки, это не работает. Оба вызова достигают метода ShowImage.

Любая помощь будет оценена по достоинству. Спасибо вам всем.

EDIT 1: GridView инкапсулирован в GridViewWrapper (там я создаю столбцы динамически, используя комбинацию свойств класса, полученных путем отражения, и сохраненных метаданных), этот класс имеет слишком много кода, чтобы поделиться здесь, и я не думаю причина в этом. Кроме того, я выполнил в режиме отладки и прошел через него шаг за шагом каждый соответствующий метод внутри этого.

Метод добавления столбца:

CustomColumnTemplate customTemplate = CustomTemplates.FirstOrDefault(f => f.columnName == metadata.ColumnIdName);

gridView.Columns.Add(new GridViewDataColumn()
{
    FieldName = metadata.ColumnIdName,
    VisibleIndex = GetVisibleIndexByColumnIdName(metadata.ColumnIdName),
    Caption = metadata.Caption,
    Width = new Unit(DefaultColumnWidth, UnitType.Pixel),
    DataItemTemplate = customTemplate == null ? null : customTemplate.template
});

Я убедился, что метод ShowImage работает, но он ведет себя так, как будто метод UpdatePanel1 не был обновлен.


person Diego Rafael Souza    schedule 18.01.2018    source источник
comment
Я не вижу ASPxGridView в вашем коде. Возможно, он инкапсулирован в GridViewWrapper. Можете ли вы показать, как вы размещаете кнопку внутри сетки? Или, что еще лучше, отправьте запрос в службу поддержки со всеми подробностями в службу поддержки DevExpress. Они отвечают быстро   -  person Vladimir    schedule 19.01.2018
comment
Спасибо за проверку @Vladimir. Я добавил некоторые сведения о GridViewWrapper. Кнопка вставляется через пользовательский шаблон при рендеринге каждой строки. Я не думаю, что это ошибка, я думаю, что здесь есть что-то концептуальное, что мне не хватает, но отправить запрос в службу поддержки — хорошая идея. Я сделаю это в ближайшее время.   -  person Diego Rafael Souza    schedule 19.01.2018


Ответы (2)


ASPxGridView сохраняет информацию о столбцах в ViewState, но не сохраняет информацию о шаблонах столбцов. Это сделано специально, поскольку шаблоны могут быть очень сложными, а их сериализация делает ViewState очень огромным. Итак, если вы создаете столбцы с шаблонами во время выполнения, отключите ViewState:

ASPxGridView.EnableViewState="false"

и создайте столбцы для каждого обратного вызова:

//if (!IsPostBack)
//{
    mainGrid.CanEditItems = true;
    mainGrid.CustomTemplates.Add(new CustomColumnTemplate { columnName = "Id", template = new LinkColumn(CreateParentLink, "Go to parent") });
    mainGrid.CustomTemplates.Add(new CustomColumnTemplate { columnName = "Value", template = new ButtonColumn(ShowImage, "View Image") }); // This one doesn't works
//}
person Vladimir    schedule 24.01.2018
comment
Идеально! Это работает очень хорошо. Мне не нужно было устанавливать EnableViewState в False (когда я это сделал, это сломало много вещей в моем GridViewWrapper, и он не работал должным образом), я просто переместил дополнения шаблона за пределы !IsPostBack block. Большое Вам спасибо. - person Diego Rafael Souza; 24.01.2018

Вы использовали код ниже:

<Triggers>
    <asp:AsyncPostBackTrigger ControlID="mainGrid" />
</Triggers>

Согласно этой статье, в asp:AsyncPostBackTrigger Если свойство EventName не указано, атрибут DefaultEventAttribute элемента управления используется для определения события по умолчанию. Например, событием по умолчанию для элемента управления Button является событие Click.

mainGrid элемент управления, созданный GridViewWrapper, который не связан с элементами управления, находящимися в mainGrid. Updatepanel пытается зарегистрировать async триггер для элемента управления mainGrid, находящегося вне панели, но не может этого сделать.

решение: я думаю, что решением этой проблемы является обновление Updatepanel в методе ShowImage().

person Ali Soltani    schedule 22.01.2018
comment
Спасибо за проверку, Али Солтани. Я тоже пробовал. Как вы можете видеть в комментарии к 3-му блоку кода, // UpdatePanel1.Update(); <-- Tryin' force it to work with no success. Вызов Update выполняется без ошибок, но ничего нового не происходит. - person Diego Rafael Souza; 22.01.2018
comment
@DiegoRafaelSouza Хорошо, я этого не видел. Вы пытались изменить порядок modalImagem.Show(); и UpdatePanel1.Update();? - person Ali Soltani; 22.01.2018
comment
@DiegoRafaelSouza Вы получаете какие-либо ошибки JavaScript сразу при загрузке? Может быть что-то, что убивает javascript на странице? - person Ali Soltani; 22.01.2018
comment
@DiegoRafaelSouza Еще одна вещь: RegisterAsyncPostBackControl вы пытаетесь RegisterAsyncPostBackControl(mainGrid) как это? - person Ali Soltani; 22.01.2018
comment
Нет ошибок javascript. Не меняйте порядок и не регистрируйте сетку, так как работает асинхронное управление обратной передачей. То же поведение, что и раньше. Я почти сдаюсь и думаю о том, чтобы найти другой подход: открыть его как всплывающее окно или простую страницу. - person Diego Rafael Souza; 22.01.2018