Modal Panel Doesn’t Appear When Called by Button Inside a Grid View’s Cell
Asked Answered
H

2

7

I've struggled a lot with how to show a modal panel on click on a button inside a grid view.

To context: I have a data row with a string field that can contain a simple text or a base 64 encoded image, so I'm using a custom template to define when to show the raw content or a button "View Image". This image will be opened on a modal panel that should rise up on button click.

This is the Panel I've created as a control (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>

And this is the page and ASPxGridView where I wanna use it:

<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" />

Codebihind:

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
    }

}

The ButtonColumn template creation:

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);
        }
    }
}

The method's call at the click of btnShowImage button works fine. But when I do the same call by one ImageButton (or button) inside the gridview it doesn't work. Both calls reach the ShowImage method.

Any help would be appreciated. Thank you all.

EDIT 1: The GridView is encapsulated in GridViewWrapper (there I build the columns dynamically using a combination of class's properties gotten by reflection and stored metadata), this class have too much code to share here and I do not think it's the reason. Also, I've executed in debug mode and passed thru it step by step every relevant method inside this one.

The column add method:

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
});

I've made sure the ShowImage method is being hitten, but it behaves like the UpdatePanel1 isn't have been updated

Hanford answered 18/1, 2018 at 19:3 Comment(2)
I do not see ASPxGridView in your code. Possibly, it is encapsulated in GridViewWrapper. Can you show how you place the button inside the grid? Or even better, submit a support ticket with all the details to DevExpress support. They reply quicklyToussaint
Thank you for check @Vladimir. I've added some details about the GridViewWrapper. The button is inserted thru the custom template, on rendering each row. I don't think it's a bug, I'm think there's something conceptual I'm missing here, but submit a support ticket is a good idea. I'll do it soon.Hanford
T
6

The ASPxGridView stores information about columns in ViewState, but does not save information about column templates. This is made on purpose since templates can be very complex and their serialization makes ViewState very huge. So, if you create columns with templates at runtime, disable ViewState:

ASPxGridView.EnableViewState="false"

and create columns on every callback:

//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
//}
Toussaint answered 24/1, 2018 at 8:0 Comment(1)
Perfect! It works greatly. I hadn't need to set EnableViewState to False (when I did it, it broke a lot of things on my GridViewWrapper and it was not worked as it had to), I'd just move the template additions to outside the !IsPostBack block. Thank you very much.Hanford
R
2

You used code below:

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

According to this article, in asp:AsyncPostBackTrigger If the EventName property is not specified, the DefaultEventAttribute attribute of the control is used to determine the default event. For example, the default event for the Button control is the Click event.

mainGrid control created by GridViewWrapper that it doesn't connected to controls that are in mainGrid. Updatepanel tries to register async trigger for the mainGrid control which is outside the panel but it can't do it.

solution: I think solution of this problem is update Updatepanel in ShowImage() method.

Redcap answered 22/1, 2018 at 13:19 Comment(5)
Thanks for check, Ali Soltani. I've tried it too. As you can see at the comment on 3rd code block, // UpdatePanel1.Update(); <-- Tryin' force it to work with no success. The Update call is executed with no error, but nothing new happens.Hanford
@DiegoRafaelSouza OK I had not seen it. Did you try to change order modalImagem.Show(); and UpdatePanel1.Update();?Redcap
@DiegoRafaelSouza Do you get any javascript errors immediately on loading? Maybe something that kills javascript on the page?Redcap
@DiegoRafaelSouza Another things is RegisterAsyncPostBackControl do you try RegisterAsyncPostBackControl(mainGrid) like this?Redcap
No javascript errors. Neither change the order nor register grid as async postback control worked. The same behavior than before. I'm almost giving up and thinking in make my way thru another approach: Open it as a popup or simple page.Hanford

© 2022 - 2024 — McMap. All rights reserved.