Condividi tramite


Aggiunta di una conferma sul lato cliente durante l'eliminazione (C#)

di Scott Mitchell

Scaricare il PDF

Nelle interfacce create finora, un utente può eliminare accidentalmente i dati facendo clic sul pulsante Elimina quando si intende fare clic sul pulsante Modifica. In questa esercitazione verrà aggiunta una finestra di dialogo di conferma sul lato client visualizzata quando si fa clic sul pulsante Elimina.

Introduzione

Nelle ultime esercitazioni è stato illustrato come usare l'architettura dell'applicazione, ObjectDataSource e i controlli Web dati in concerto per fornire funzionalità di inserimento, modifica ed eliminazione. Le interfacce di eliminazione esaminate finora sono state composte da un pulsante Delete che, quando si fa clic, provoca un postback e richiama il metodo ObjectDataSource s Delete() . Il Delete() metodo richiama quindi il metodo configurato dal livello di logica di business, che propaga la chiamata al livello di accesso ai dati, eseguendo l'istruzione effettiva DELETE al database.

Anche se questa interfaccia utente consente ai visitatori di eliminare i record tramite i controlli GridView, DetailsView o FormView, non dispone di alcuna sorta di conferma quando l'utente fa clic sul pulsante Elimina. Se un utente fa accidentalmente clic sul pulsante Elimina quando ha lo scopo di fare clic su Modifica, il record che intende aggiornare verrà invece eliminato. Per evitare questo problema, in questa esercitazione verrà aggiunta una finestra di dialogo di conferma sul lato client visualizzata quando si fa clic sul pulsante Elimina.

La funzione JavaScript confirm(string) visualizza il parametro di input della stringa come testo all'interno di una finestra di dialogo modale fornita con due pulsanti: OK e Annulla (vedere la figura 1). La confirm(string) funzione restituisce un valore booleano a seconda del pulsante su cui viene fatto clic (truese l'utente fa clic su OK e false se fa clic su Annulla).

Il metodo confirm(string) JavaScript visualizza una casella di messaggio modale Client-Side

Figura 1: Il metodo JavaScript confirm(string) visualizza una casella di messaggio modale Client-Side

Durante l'invio di un modulo, se viene restituito un valore di false da un gestore eventi sul lato client, l'invio del modulo viene annullato. Usando questa funzionalità, è possibile fare in modo che il gestore eventi del lato client onclick del pulsante Delete restituisca il valore di una chiamata a confirm("Are you sure you want to delete this product?"). Se l'utente fa clic su Annulla, confirm(string) restituirà false, causando l'annullamento dell'invio del modulo. Senza postback, il prodotto su cui è stato fatto clic sul pulsante Elimina non verrà eliminato. Tuttavia, se l'utente fa clic su OK nella finestra di dialogo di conferma, il postback continuerà senza interruzioni e il prodotto verrà eliminato. Per altre informazioni su questa tecnica, vedere Uso del metodo s confirm() JavaScript per controllare l'invio di moduli .

L'aggiunta del necessario script lato client-side differisce leggermente se si utilizzano i template rispetto a quando si utilizza un CommandField. Di conseguenza, in questa esercitazione verrà esaminato sia un esempio di FormView che gridView.

Annotazioni

Usando tecniche di conferma lato client, come quelle descritte in questa esercitazione, si presuppone che gli utenti visitino con browser che supportano JavaScript e che abbiano JavaScript abilitato. Se una di queste ipotesi non è vera per un determinato utente, facendo clic sul pulsante Elimina verrà immediatamente generato un postback (non viene visualizzata una casella di messaggio di conferma).

Passaggio 1: Creazione di un controllo FormView che supporta l'eliminazione

Per iniziare, aggiungere un controllo FormView alla pagina ConfirmationOnDelete.aspx nella cartella EditInsertDelete, associandolo a un nuovo ObjectDataSource che recupera le informazioni sul prodotto tramite il metodo ProductsBLL della classe GetProducts(). Configurare anche ObjectDataSource in modo che il metodo della classe ProductsBLL sia mappato al metodo di ObjectDataSource DeleteProduct(productID); assicurarsi che le liste a discesa relative a INSERT e UPDATE siano impostate su (Nessuno). Infine, selezionare la casella di controllo Abilita Paging nello smart tag FormView.

Dopo questi passaggi, il nuovo markup dichiarativo di ObjectDataSource sarà simile al seguente:

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
    DeleteMethod="DeleteProduct" OldValuesParameterFormatString="original_{0}"
    SelectMethod="GetProducts" TypeName="ProductsBLL">
    <DeleteParameters>
        <asp:Parameter Name="productID" Type="Int32" />
    </DeleteParameters>
</asp:ObjectDataSource>

Come negli esempi precedenti che non usano la concorrenza ottimistica, prendi un momento per cancellare la proprietà OldValuesParameterFormatString di ObjectDataSource.

Poiché è stato associato a un controllo ObjectDataSource che supporta solo l'eliminazione, FormView offre ItemTemplate solo il pulsante Elimina, senza i pulsanti Nuovo e Aggiorna. Il markup dichiarativo di FormView, tuttavia, include un superfluo EditItemTemplate e InsertItemTemplate, che può essere rimosso. Dedica qualche istante alla personalizzazione di ItemTemplate così da mostrare solo un sottogruppo dei campi dati del prodotto. Ho configurato il mio per mostrare il nome del prodotto in un'intestazione <h3> sopra i relativi nomi fornitore e categoria (insieme al pulsante Elimina).

<asp:FormView ID="FormView1" AllowPaging="True" DataKeyNames="ProductID"
    DataSourceID="ObjectDataSource1" runat="server">
    <ItemTemplate>
        <h3><i><%# Eval("ProductName") %></i></h3>
        <b>Category:</b>
        <asp:Label ID="CategoryNameLabel" runat="server"
            Text='<%# Eval("CategoryName") %>'>
        </asp:Label><br />
        <b>Supplier:</b>
        <asp:Label ID="SupplierNameLabel" runat="server"
            Text='<%# Eval("SupplierName") %>'>
        </asp:Label><br />
        <asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
            CommandName="Delete" Text="Delete">
        </asp:LinkButton>
    </ItemTemplate>
</asp:FormView>

Con queste modifiche, abbiamo una pagina Web completamente funzionale che consente a un utente di attivare o disattivare i prodotti uno alla volta, con la possibilità di eliminare un prodotto semplicemente facendo clic sul pulsante Elimina. La figura 2 mostra una schermata dello stato di avanzamento finora visualizzato tramite un browser.

FormView mostra informazioni su un singolo prodotto

Figura 2: FormView mostra informazioni su un singolo prodotto (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 2: Chiamata della funzione confirm(string) dall'evento onclick del pulsante 'Elimina' Client-Side

Dopo aver creato FormView, il passaggio finale consiste nel configurare il pulsante Elimina in modo che quando viene fatto clic dal visitatore, viene richiamata la funzione JavaScript confirm(string) . L'aggiunta di script lato client a un evento lato client di un Button, LinkButton o ImageButton può essere eseguita tramite l'uso di onclick, che è una novità di ASP.NET 2.0. Poiché si vuole avere il valore della confirm(string) funzione restituita, è sufficiente impostare questa proprietà su: return confirm('Are you certain that you want to delete this product?');

Dopo questa modifica, la sintassi dichiarativa di Delete LinkButton dovrebbe essere simile alla seguente:

<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
    CommandName="Delete" Text="Delete"
    OnClientClick="return confirm('Are you certain you want to delete this product?');">
</asp:LinkButton>

È tutto qui! La figura 3 mostra una schermata di questa conferma in azione. Facendo clic sul pulsante Elimina viene visualizzata la finestra di dialogo di conferma. Se l'utente fa clic su Annulla, il postback viene annullato e il prodotto non viene eliminato. Se, tuttavia, l'utente fa clic su OK, il postback continua e viene richiamato il metodo ObjectDataSource, Delete() fino all'eliminazione del record del database.

Annotazioni

La stringa passata alla confirm(string) funzione JavaScript è delimitata da apostrofi (anziché tra virgolette). In JavaScript le stringhe possono essere delimitate usando entrambi i caratteri. In questo caso vengono usati apostrofi in modo che i delimitatori per la stringa passata in confirm(string) non introducano ambiguità con i delimitatori usati per il valore della OnClientClick proprietà.

Viene visualizzata una conferma quando si fa clic sul pulsante Elimina

Figura 3: Viene visualizzata una conferma quando si fa clic sul pulsante Elimina (fare clic per visualizzare l'immagine a dimensione intera)

Passaggio 3: Configurazione della proprietà OnClientClick per il pulsante Elimina in un campo di comando

Quando si lavora direttamente con un controllo Button, LinkButton o ImageButton in un modello, è possibile associare una finestra di dialogo di conferma configurando semplicemente la proprietà OnClientClick per restituire i risultati della funzione JavaScript confirm(string). Tuttavia, CommandField, che aggiunge un campo di pulsanti di eliminazione a un GridView o DetailsView, non dispone di una OnClientClick proprietà che può essere impostata in modo dichiarativo. È invece necessario fare riferimento a livello di codice al pulsante Elimina nel gestore eventi appropriato di GridView o DetailsView e quindi impostarne la proprietà.

Annotazioni

Quando si imposta la proprietà del pulsante Elimina nel gestore eventi appropriato, è possibile accedere ai dati che erano associati al record corrente. Ciò significa che possiamo ampliare il messaggio di conferma per includere i dettagli del record specifico, come, "Sei sicuro di voler eliminare il prodotto Chai?" Tale personalizzazione è anche possibile nei modelli usando la sintassi di associazione dati.

Per provare a impostare la OnClientClick proprietà per i pulsanti Elimina in un campo di comando, è possibile aggiungere un controllo GridView alla pagina. Configurare questo controllo GridView per l'uso dello stesso controllo ObjectDataSource utilizzato da FormView. Inoltre, limitare i BoundFields di GridView in modo da includere solo il nome, la categoria e il fornitore del prodotto. Infine, selezionare la casella di controllo Abilita eliminazione dal smart tag di GridView. Verrà aggiunto un oggetto CommandField all'insieme gridView Columns con la relativa ShowDeleteButton proprietà impostata su true.

Dopo aver apportato queste modifiche, il markup dichiarativo di GridView dovrebbe essere simile al seguente:

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
    DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
    <Columns>
        <asp:CommandField ShowDeleteButton="True" />
        <asp:BoundField DataField="ProductName" HeaderText="Product"
            SortExpression="ProductName" />
        <asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True"
            SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True"
            SortExpression="SupplierName" />
    </Columns>
</asp:GridView>

CommandField contiene una singola istanza di Delete LinkButton accessibile a livello di codice dal gestore eventi di RowDataBound GridView. Una volta fatto riferimento, possiamo impostare di conseguenza la sua OnClientClick proprietà. Creare un gestore eventi per l'evento RowDataBound usando il codice seguente:

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // reference the Delete LinkButton
        LinkButton db = (LinkButton)e.Row.Cells[0].Controls[0];

        // Get information about the product bound to the row
        Northwind.ProductsRow product =
            (Northwind.ProductsRow) ((System.Data.DataRowView) e.Row.DataItem).Row;

        db.OnClientClick = string.Format(
            "return confirm('Are you certain you want to delete the {0} product?');",
            product.ProductName.Replace("'", @"\'"));
    }
}

Questo gestore eventi funziona con le righe di dati (quelle che avranno il pulsante Elimina) e inizia facendo riferimento a livello di codice al pulsante Elimina. In generale, usare il modello seguente:

ButtonType obj = (ButtonType) e.Row.Cells[commandFieldIndex].Controls[controlIndex];

ButtonType è il tipo di pulsante utilizzato da CommandField - Button, LinkButton o ImageButton. Per impostazione predefinita, CommandField usa LinkButtons, ma può essere personalizzato tramite CommandField s ButtonType property. CommandFieldIndex è l'indice ordinale dell'oggetto CommandField all'interno dell'insieme GridView, Columns mentre controlIndex è l'indice del pulsante Delete all'interno dell'insieme CommandField.Controls Il valore controlIndex dipende dalla posizione del pulsante rispetto ad altri pulsanti in CommandField. Ad esempio, se l'unico pulsante visualizzato in CommandField è il pulsante Elimina, usare un indice pari a 0. Se, tuttavia, è presente un pulsante Modifica che precede il pulsante Elimina, usare un indice pari a 2. Il motivo per cui viene utilizzato un indice pari a 2 è dovuto al fatto che due controlli vengono aggiunti dal campo di comando prima del pulsante Elimina: il pulsante Modifica e un oggetto LiteralControl utilizzato per aggiungere spazio tra i pulsanti Modifica ed Elimina.

Per questo esempio particolare, CommandField usa LinkButtons e, essendo il campo più a sinistra, ha un commandFieldIndex pari a 0. Poiché non sono presenti altri pulsanti, ma il pulsante Elimina in CommandField, viene usato un controlloIndex pari a 0.

Dopo aver fatto riferimento al pulsante Elimina in CommandField, si afferrano quindi le informazioni sul prodotto associato alla riga GridView corrente. Infine, impostiamo la proprietà del OnClientClick pulsante Elimina sul codice JavaScript appropriato, che include il nome del prodotto. Poiché la stringa JavaScript passata alla confirm(string) funzione è delimitata usando apostrofi, è necessario eseguire l'escape di qualsiasi apostrofo visualizzato all'interno del nome del prodotto. In particolare, qualsiasi apostrofo nel nome del prodotto viene preceduto da "\'".

Dopo aver completato queste modifiche, facendo clic su un pulsante Elimina in GridView viene visualizzata una finestra di dialogo di conferma personalizzata (vedere la figura 4). Come per la casella di messaggio di conferma da FormView, se l'utente fa clic su Annulla il postback viene annullato, impedendo così l'eliminazione.

Annotazioni

Questa tecnica può essere usata anche per accedere a livello di codice al pulsante Elimina nel CommandField in un componente DetailsView. Per DetailsView, tuttavia, è necessario creare un gestore eventi per l'evento DataBound , poiché DetailsView non ha un RowDataBound evento.

Facendo clic sul pulsante Elimina di GridView viene visualizzata una finestra di dialogo di conferma personalizzata

Figura 4: Facendo clic sul pulsante Elimina di GridView viene visualizzata una finestra di dialogo di conferma personalizzata (fare clic per visualizzare l'immagine a dimensione intera)

Uso di TemplateFields

Uno degli svantaggi di CommandField è che i pulsanti devono essere raggiunti tramite l'indicizzazione, e l'oggetto risultante deve essere convertito nel tipo di pulsante appropriato (Button, LinkButton o ImageButton). L'uso di "numeri magici" e tipi codificati in modo fisso può portare a problemi che non possono essere individuati fino al momento dell'esecuzione. Ad esempio, se si o un altro sviluppatore, aggiunge nuovi pulsanti a CommandField in un certo momento in futuro (ad esempio un pulsante Modifica) o modifica la ButtonType proprietà, il codice esistente verrà comunque compilato senza errori, ma visitando la pagina potrebbe causare un'eccezione o un comportamento imprevisto, a seconda del modo in cui il codice è stato scritto e quali modifiche sono state apportate.

Un approccio alternativo consiste nel convertire GridView e DetailsView s CommandFields in TemplateFields. Verrà generato un TemplateField che include un ItemTemplate, con un controllo LinkButton (o Button o ImageButton) per ciascun pulsante nel CommandField. Queste proprietà dei pulsanti OnClientClick possono essere assegnate in modo dichiarativo, come si è visto con FormView o possono essere accessibili a livello di codice nel gestore eventi appropriato DataBound usando il modello seguente:

ButtonType obj = (ButtonType) e.Row.FindControl("controlID");

Dove controlID è il valore della proprietà del ID pulsante. Anche se questo modello richiede ancora un tipo codificato in modo fisso per il cast, elimina la necessità di indicizzazione, consentendo al layout di modificarsi senza generare un errore in fase di esecuzione.

Riassunto

La funzione JavaScript confirm(string) è una tecnica comunemente usata per controllare il flusso di lavoro di invio di moduli. Quando viene eseguita, la funzione visualizza una finestra di dialogo modale sul lato client che include due pulsanti, OK e Annulla. Se l'utente fa clic su OK, la confirm(string) funzione restituisce true. Se si fa clic su Annulla, viene restituito false. Questa funzionalità, associata al comportamento di un browser per annullare un invio di modulo se un gestore eventi durante il processo di invio restituisce false, può essere usato per visualizzare una finestra di messaggio di conferma durante l'eliminazione di un record.

La funzione confirm(string) può essere associata a un gestore eventi lato client onclick del controllo Web Button tramite la proprietà OnClientClick del controllo. Quando si usa un pulsante Elimina in un modello, in uno dei modelli di FormView o in un oggetto TemplateField in DetailsView o GridView, questa proprietà può essere impostata in modo dichiarativo o programmatico, come illustrato in questa esercitazione.

Buon programmatori!

Informazioni sull'autore

Scott Mitchell, autore di sette libri ASP/ASP.NET e fondatore di 4GuysFromRolla.com, ha lavorato con le tecnologie Web Microsoft dal 1998. Scott lavora come consulente indipendente, formatore e scrittore. Il suo ultimo libro è Sams Teach Yourself ASP.NET 2.0 in 24 ore. Può essere raggiunto a mitchell@4GuysFromRolla.com.