Modificare dati in un GridView

Il controllo GridView di Asp.Net consente anche la modifica e l'inserimento di righe. Questo articolo è composto da esempi che comprendono la validazione degli input dell'utente e la gestione della modifica contemporanea da parte di più utenti.

Prima di procedere con questo articolo bisogna sapere come configurare un SqlDataSource per poter supportare la modifica dei dati.

La modifica, l'inserimento e la cancellazione dei dati possono essere attivati dallo Smart Task Menu del GridView attivando le relative checkbox.

Pulsanti di modifica e cancellazione in due colonne separate

Per default Visual Studio mette i pulsanti di modifica e cancellazione in un campo unico. E' però possibile metterli in due colonne separate aggiungendo due colonne di tipo CommandField.

<asp:GridView ID="GridView_Update" runat="server"
	AutoGenerateColumns="False" DataKeyNames="ID" DataSourceID="SqlDataSource1"
	HeaderStyle-BackColor="#006600" HeaderStyle-ForeColor="White">
	<Columns>
		<asp:BoundField DataField="ID" HeaderText="ID" ReadOnly="True" SortExpression="ID" />
		<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
		<asp:BoundField DataField="Link" HeaderText="Link" SortExpression="Link" />
		<asp:CheckBoxField DataField="Published" HeaderText="Published" SortExpression="Published" />
		<asp:CommandField ShowEditButton="True" />
		<asp:CommandField CausesValidation="False" ShowDeleteButton="True" />
	</Columns>
</asp:GridView>

Modifica dati GridView Asp.Net con validazione input

Validare i dati significa controllare che il formato dei dati di input sia valido prima di tentare di inserirli nel data base. Ad esempio nel campo Nome non si possono accettare caratteri numerici, e non si possono lasciare vuoti i campi obbligatori.

Trasformare i vari campi del GridView in TemplateFields:

Smart Task >> Edit Columns >> Selezionare la colonna >> Convert this field into a TemplateField

Ora è possibile usare i controlli di validazione Asp.Net come in un qualunque form.

<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
		DataKeyNames="ID" DataSourceID="SqlDataSource1">
	<Columns>
		<asp:TemplateField HeaderText="ID" SortExpression="ID">
			<ItemTemplate>
				<asp:Label ID="Label1" runat="server" Text='<%# Bind("ID") %>'></asp:Label>
			</ItemTemplate>
			<EditItemTemplate>
				<asp:Label ID="lblId" runat="server" Text='<%# Eval("ID") %>'></asp:Label>
			</EditItemTemplate>
		</asp:TemplateField>
		<asp:TemplateField HeaderText="Name" SortExpression="Name">
			<ItemTemplate>
				<asp:Label ID="Label2" runat="server" Text='<%# Bind("Name") %>'></asp:Label>
			</ItemTemplate>
			<EditItemTemplate>
				<asp:TextBox ID="txtName" runat="server" Text='<%# Bind("Name") %>'></asp:TextBox>
				<asp:RequiredFieldValidator ID="rfvName" runat="server"
					ErrorMessage="Il campo Nome è obbligatorio" ControlToValidate="txtName" Text="*">
				</asp:RequiredFieldValidator>
			</EditItemTemplate>
		</asp:TemplateField>
		<asp:TemplateField HeaderText="Link" SortExpression="Link">
			<ItemTemplate>
				<asp:Label ID="Label3" runat="server" Text='<%# Bind("Link") %>'></asp:Label>
			</ItemTemplate>
			<EditItemTemplate>
				<asp:TextBox ID="txtLink" runat="server" Text='<%# Bind("Link") %>'></asp:TextBox>
				<asp:RequiredFieldValidator ID="rfvLink" runat="server"
					ErrorMessage="Il campo Link è obbligatorio" Text="*" ControlToValidate="txtLink">
				</asp:RequiredFieldValidator>
			</EditItemTemplate>
		</asp:TemplateField>
		<asp:TemplateField HeaderText="Published" SortExpression="Published">
			<ItemTemplate>
				<asp:CheckBox ID="CheckBox1" runat="server" Checked='<%# Bind("Published") %>'
					Enabled="false" />
			</ItemTemplate>
			<EditItemTemplate>
				<asp:CheckBox ID="CheckBox1" runat="server" Checked='<%# Bind("Published") %>' />
			</EditItemTemplate>
		</asp:TemplateField>
		<asp:CommandField ShowEditButton="True" />
	</Columns>
	<HeaderStyle BackColor="#006600" ForeColor="White" />
</asp:GridView>
<asp:ValidationSummary ID="ValidationSummary1" runat="server" />

Eliminare righe

Purtroppo per default quando si cerca di eliminare una riga non viene richiesta nessuna conferma. Occorre implementare questa funzionalità manualmente usando JavaScript.

Si aggiunge al GridView un campo di tipo TemplateField nel quale si inserisce un'immagine, un bottone o un link con il parametro CommandName="Delete" e si specifica anche OnClientClick.

Ecco un esempio:

<asp:BoundField DataField="Picture" HeaderText="Picture" SortExpression="Picture" />
<asp:TemplateField>
	<ItemTemplate>
		<asp:LinkButton ID="LinkButton1" runat="server" CommandName="Delete" 
			OnClientClick="return confirm('Sei sicuro di voler eliminare questo record?');">Elimina</asp:LinkButton>
	</ItemTemplate>
</asp:TemplateField>

Gestione della Concurrency

E' possibile che due diversi utenti tentino di modificare lo stesso record contemporanemante. In questo esempio viene gestita una Concurrency di tipo ottimistico, nella quale si avvisa l'utente che sta tentando di modificare dei dati non aggiornati.

  • Creare un SqlDataSource di tipo Ottimistico

    Advanced >> Use optimistic concurrency

  • Abilitare la modifica e l'eliminazione

    GridView Tasks >> Enable Edting e Enable Deleting

  • Gestire gli eventi RowUpdated e RowDeleted del GridView per determinare se effettivamente la riga è stata modificata
  • In caso negativo informare l'utente e suggerire di riprovare
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConflictDetection="CompareAllValues" 
	ConnectionString="<%$ ConnectionStrings:Pubs_DB %>" 
	DeleteCommand="DELETE FROM [authors] WHERE [au_id] = @original_au_id AND [au_lname] = @original_au_lname AND [au_fname] = @original_au_fname AND [phone] = @original_phone AND [contract] = @original_contract"
	InsertCommand="INSERT INTO [authors] ([au_id], [au_lname], [au_fname], [phone], [contract]) VALUES (@au_id, @au_lname, @au_fname, @phone, @contract)"
	OldValuesParameterFormatString="original_{0}" 
	SelectCommand="SELECT [au_id], [au_lname], [au_fname], [phone], [contract] FROM [authors] ORDER BY [au_lname]" 
	UpdateCommand="UPDATE [authors] SET [au_lname] = @au_lname, [au_fname] = @au_fname, [phone] = @phone, [contract] = @contract WHERE [au_id] = @original_au_id AND [au_lname] = @original_au_lname AND [au_fname] = @original_au_fname AND [phone] = @original_phone AND [contract] = @original_contract">
	
	<DeleteParameters>
		<asp:Parameter Name="original_au_id" Type="String" />
		<asp:Parameter Name="original_au_lname" Type="String" />
		<asp:Parameter Name="original_au_fname" Type="String" />
		<asp:Parameter Name="original_phone" Type="String" />
		<asp:Parameter Name="original_contract" Type="Boolean" />
	</DeleteParameters>
	<InsertParameters>
		<asp:Parameter Name="au_id" Type="String" />
		<asp:Parameter Name="au_lname" Type="String" />
		<asp:Parameter Name="au_fname" Type="String" />
		<asp:Parameter Name="phone" Type="String" />
		<asp:Parameter Name="contract" Type="Boolean" />
	</InsertParameters>
	<UpdateParameters>
		<asp:Parameter Name="au_lname" Type="String" />
		<asp:Parameter Name="au_fname" Type="String" />
		<asp:Parameter Name="phone" Type="String" />
		<asp:Parameter Name="contract" Type="Boolean" />
		<asp:Parameter Name="original_au_id" Type="String" />
		<asp:Parameter Name="original_au_lname" Type="String" />
		<asp:Parameter Name="original_au_fname" Type="String" />
		<asp:Parameter Name="original_phone" Type="String" />
		<asp:Parameter Name="original_contract" Type="Boolean" />
	</UpdateParameters>
</asp:SqlDataSource>

<asp:GridView ID="GridView_Concurrency" runat="server" AutoGenerateColumns="False" 
		DataKeyNames="au_id"
		DataSourceID="SqlDataSource1">
	<Columns>
		<asp:CommandField ShowDeleteButton="True" ShowEditButton="True" />
		<asp:BoundField DataField="au_id" HeaderText="au_id" ReadOnly="True" SortExpression="au_id" />
		<asp:BoundField DataField="au_lname" HeaderText="au_lname" SortExpression="au_lname" />
		<asp:BoundField DataField="au_fname" HeaderText="au_fname" SortExpression="au_fname" />
		<asp:BoundField DataField="phone" HeaderText="phone" SortExpression="phone" />
		<asp:CheckBoxField DataField="contract" HeaderText="contract" SortExpression="contract" />
	</Columns>
	<HeaderStyle BackColor="#006600" ForeColor="White" />
</asp:GridView>
<br />
<asp:Label ID="lblError" runat="server" ForeColor="#CC3300"></asp:Label>

Code behind: se non ci sono errori ma non è stata modificata nessuna riga, quasi sicuramente siamo di fronte a un problema di concurrency.

Protected Sub GridView_Concurrency_RowDeleted(sender As Object, e As System.Web.UI.WebControls.GridViewDeletedEventArgs) Handles GridView_Concurrency.RowDeleted
	If e.Exception Is Nothing And e.AffectedRows = 0 Then
		lblError.Text = "Il record è già stato eliminato o aggiornato da un altro utente. Riprovare."
	End If
End Sub

Protected Sub GridView_Concurrency_RowUpdated(sender As Object, e As System.Web.UI.WebControls.GridViewUpdatedEventArgs) Handles GridView_Concurrency.RowUpdated
	If e.Exception Is Nothing And e.AffectedRows = 0 Then
		lblError.Text = "Il record è già stato eliminato o aggiornato da un altro utente. Riprovare."
	End If
End Sub

Autore: Sergio Roberto Boarina