Sloupec v GridView s potvrzením vymazání záznamu (na klientovi)
Jestliže chcete mít v GridView sloupec, který uživatele požádá na klientovi (s využitím JavaScriptu) o potvrzeni smazání záznamu, je doporučeno používat TemplateField, jehož šablona ItemTemplate obsahuje ve vlastnosti OnClientClick tlačítka klientský kód.
<asp
:TemplateField ShowHeader="False">
<ItemTemplate>
<asp:ImageButton ID="ImageButton1" runat="server" CausesValidation="False" CommandName="Delete" ImageUrl="~/Images/delete.gif" OnClientClick="javascript:return confirm('Opravdu smazat záznam?');" />
</ItemTemplate>
</asp:TemplateField>
ButtonField by byl sice vhodnější, ale tvůrci ASP.NET zadání kódu v JavaScriptu pro ButtonField nepodporují. Třída ButtonField nenabízí ani přístup k vlastnostem prvku Button, který je vyrenderován na každém řádku GridView.
Chceme-li napsat svůj vlastní typový sloupec pro mazání záznamů, který budeme používat ve všech svých projektech, použijeme třídu ButtonField alespoň jako předka svého nového sloupce a lehce "dirty" kódem v v přepsané metodě InitializeCell přidáme tlačítku vytvořenému v "našem" sloupci pro každý řádek GridView jednoduchý kód v JavaScriptu, jenž bude vyžadovat od uživatele potvrzení smazání záznamu.
/// <summary>
/// Nový typ sloupce pro GridView obsahující tlačítko pro smazání záznamu s potvrzením na klientovi (JS)
/// </summary>
public class DeleteButtonField : ButtonField
{
#region Private constants
private const string DEFAULT_CONFIRM_MESSAGE = "Opravdu smazat záznam?";
private const string DELETE_COMMAND = "Delete";
private const string DELETE_JS = "javascript: if (!confirm('{0}')) return false;";
#endregion Private constants
public DeleteButtonField() : base()
{
}
#region Public properties
/// <summary>
///Text varování, které se má zobrazit uživateli při pokusu vymazat záznam
/// </summary>
public string ConfirmMessage
{
get
{
string confirmMessage = (string)ViewState["ConfirmMessage"];
if (confirmMessage == null)
{
return DEFAULT_CONFIRM_MESSAGE;
}
return (confirmMessage);
}
set
{
ViewState["ConfirmMessage"] = value;
}
}
#endregion Public properties
#region Public properties
/// <summary>
/// Metoda volaná při incializaci buňky Gridu
/// </summary>
/// <param name="cell">Inicializovaná buňka</param>
/// <param name="cellType">Typ buňky</param>
/// <param name="rowState">Stav řádku buňky</param>
/// <param name="rowIndex">Index řádku buňky</param>
public override void InitializeCell(DataControlFieldCell cell, DataControlCellType cellType, DataControlRowState rowState, int rowIndex)
{
base.InitializeCell(cell, cellType, rowState, rowIndex);
if (cell.Controls.Count > 0)
{
IButtonControl control = cell.Controls[0] as IButtonControl;
if (control != null)
{
control.CommandName = DELETE_COMMAND;
LinkButton lb = control as LinkButton;
Button btn = control as Button;
ImageButton iBtn = control as ImageButton;
string fullConfirmMessage = String.Format(DELETE_JS, ConfirmMessage);
if (lb != null)
{
lb.OnClientClick = fullConfirmMessage;
}
else if (btn != null)
{
btn.OnClientClick = fullConfirmMessage;
}
else if (iBtn != null)
{
iBtn.OnClientClick = fullConfirmMessage;
}
}
}
}
#endregion Public methods
}
Kód není nijak složitý. Kromě konstant, jejichž význam je dostatečně zřejmý z jejich názvu, máme v našem novém sloupci vlastnost ConfirmMessage, která obsahuje text zobrazovaný v dialogu pro potvrzení smazání záznamu. V metodě InitializeCell nejdříve zavoláme implementaci InitializeCell třídy ButtonField. Poté zjistíme, jestli buňka gridu (cell) obsahuje nějaké ovládací prvky. Jestliže ne, byla metoda volána pro řádek reprezentující záhlaví nebo zápatí gridu, a v ní žádné tlačítko nebude. Když buňka obsahuje alespoň jeden ovládací prvek, zjistíme zda první prvek v kolekci1 je typu IButtonControl (rozhraní IButtonControl implementují třídy LinkButton, Button i ImageButton) a nastavíme jeho vlastnost CommandName na text Delete. Jak asi víte, řetězec "Delete" je jedním z příkazů, které GridView rozeznává a speciálně ošetřuje, takže při bublání událost Click tlačítka s CommandName nastaveným na "Delete" je vyvolána událost RowDeleting (a případně další) místo generické události RowCommand.
Protože rozhraní IButtonControl nenabízí vlastnost OnClientClick pro zadání potvrzujícího kódu v Javascriptu, musíme přetypovat na konkrétní třídu Button a poté teprve můžeme použít vlastnost OnClientClick. Další "dirty" kód - byl bych raději, kdyby byla vlastnost OnClientClick přímo součástí rozhraní IButtonControl, anebo by mohl existovat společný abstraktní předek s vlastností OnClientClick pro třídy ImageButton, LinkButton a Button.
Nový sloupec ve svém projektu použijete takto:
Zaregistrujete nový sloupec na stránce jako běžný serverový ovládací prvek zadáním jména jeho assembly, jmenného prostoru a rezervací prefixu značek pro své prvky v direktivě @Register.
<%
@ Register Assembly="Rstein.Web.Ui" Namespace="Rstein.Web.Ui" TagPrefix="custom" %>
Sloupec přidejte do kolekce Columns prvku GridView a nastavte dle svých požadavků vlastnosti sloupce.
<asp
:GridView ID="GridView1" runat="server" AutoGenerateColumns="False" OnRowDeleting="GridView1_RowDeleting">
<Columns>
<custom:DeleteButtonField Text="Smazat" ButtonType="Button" ConfirmMessage="Smazat záznam?"/>
</Columns>
</asp:GridView>
Příště si ukážeme, jak podobné sloupce pro Grid udělat lépe s využitím šablon vytvořených v kódu a také doplníme pro své sloupce kompletní podporu pro design time.
- Zde je ten zmiňovaný "dirty" postup. I když jsem si ověřil Reflectorem, že prvním prvkem kolekce je vždy IButtonControl vytvářený třídou ButtonColumn, jde o typický případ svazování svého kódu s kódem, jehož změny nemáte pod kontrolou a přitom se nespoléháte jen na jeho "typově bezpečné" veřejné API, takže se v dalších verzích můžete dočkat nepříjemných překvapení :(
Friday, 19 May 2006 17:44:04 (Central Europe Standard Time, UTC+01:00)
.NET Framework | ASP.NET