当网格视图的单元格内的按钮调用时,模态面板不会出现

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

我一直在努力解决如何在单击网格视图内的按钮时显示模态面板的问题。

根据上下文:我有一个带有字符串字段的数据行,该字段可以包含简单文本或 base 64 编码图像,因此我使用自定义模板来定义何时显示原始内容或按钮 "View Image"。此图像将在模态面板上打开,该面板应在单击按钮时出现。

这是我作为控件创建的面板 (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 按钮时的方法调用工作正常。但是,当我通过 gridview 中的一个 ImageButton(或按钮)执行相同的调用时,它不起作用。两个调用都到达 ShowImage 方法。

如有任何帮助,我们将不胜感激。谢谢大家。

编辑 1: GridView 被封装在 GridViewWrapper 中(我使用反射获得的 class 的属性和存储的元数据的组合动态构建列),这个 class 有太多代码在这里分享我不认为这是原因。此外,我已经在调试模式下执行并逐步通过了其中的每个相关方法。

列添加方法:

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 尚未更新

您使用了以下代码:

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

根据this article,在asp:AsyncPostBackTrigger中如果没有指定EventName属性,则使用控件的DefaultEventAttribute属性来确定默认事件。例如,Button 控件的默认事件是 Click 事件。

mainGrid 控件由 GridViewWrapper 创建,它没有连接到 mainGrid 中的控件。 Updatepanel 尝试为面板外的 mainGrid 控件注册 async 触发器,但无法完成。

解决方法: 我认为这个问题的解决方案是在 ShowImage() 方法中更新 Updatepanel

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