Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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

like image 973
Diego Rafael Souza Avatar asked Jan 18 '18 19:01

Diego Rafael Souza


1 Answers

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
//}
like image 140
Vladimir Avatar answered Sep 21 '22 13:09

Vladimir