J'ai un GridView
affichant les enregistrements des personnes. Je veux montrer conditionnellement un CommandField
ou ButtonField
basé sur une propriété de l'enregistrement sous-jacent. L'idée est de n'autoriser l'exécution d'une commande que sur des personnes spécifiques.
Quelle est la meilleure façon de procéder? Je préfère une solution déclarative à une solution procédurale.
Tout d'abord, convertissez votre ButtonField
ou CommandField
en TemplateField
, puis liez la propriété Visible
du bouton à une méthode qui implémente la logique métier:
<asp:GridView runat="server" ID="GV1" AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="Name" HeaderText="Name" />
<asp:BoundField DataField="Age" HeaderText="Age" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button runat="server" Text="Reject"
Visible='<%# IsOverAgeLimit((Decimal)Eval("Age")) %>'
CommandName="Select"/>
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
Ensuite, dans le code derrière, ajoutez la méthode:
protected Boolean IsOverAgeLimit(Decimal Age) {
return Age > 35M;
}
L'avantage ici est que vous pouvez tester la méthode IsOverAgeLimit
assez facilement.
cela pourrait être fait lorsque l'événement RowDataBound
se déclenche
protected void GridView_RowDataBound(Object sender, GridViewRowEventArgs e)
{
if(e.Row.RowType == DataControlRowType.DataRow)
{
// Hide the edit button when some condition is true
// for example, the row contains a certain property
if (someCondition)
{
Button btnEdit = (Button)e.Row.FindControl("btnEdit");
btnEdit.Visible = false;
}
}
}
Voici une page de démonstration
markup
<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="DropDownDemo._Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
<title>GridView OnRowDataBound Example</title>
</head>
<body>
<form id="form1" runat="server">
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="false">
<Columns>
<asp:BoundField HeaderText="Name" DataField="name" />
<asp:BoundField HeaderText="Age" DataField="age" />
<asp:TemplateField>
<ItemTemplate>
<asp:Button ID="BtnEdit" runat="server" Text="Edit" />
</ItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>
</form>
</body>
</html>
Code derrière
using System;
using System.Collections.Generic;
using System.Web.UI.WebControls;
namespace GridViewDemo
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
GridView1.DataSource = GetCustomers();
GridView1.DataBind();
}
protected override void OnInit(EventArgs e)
{
GridView1.RowDataBound += new GridViewRowEventHandler(GridView1_RowDataBound);
base.OnInit(e);
}
void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType != DataControlRowType.DataRow) return;
int age;
if (int.TryParse(e.Row.Cells[1].Text, out age))
if (age == 30)
{
Button btnEdit = (Button) e.Row.FindControl("btnEdit");
btnEdit.Visible = false;
}
}
private static List<Customer> GetCustomers()
{
List<Customer> results = new List<Customer>();
results.Add(new Customer("Steve", 30));
results.Add(new Customer("Brian", 40));
results.Add(new Customer("Dave", 50));
results.Add(new Customer("Bill", 25));
results.Add(new Customer("Rich", 22));
results.Add(new Customer("Bert", 30));
return results;
}
}
public class Customer
{
public string Name {get;set;}
public int Age { get; set; }
public Customer(string name, int age)
{
Name = name;
Age = age;
}
}
}
Dans la démo, le bouton Modifier n'est pas visible (le balisage HTML n'est pas envoyé au client) dans les lignes où l'âge du client est de 30 ans.
Permettez-moi de partager mon approche pour ce qu'elle vaut. Pour moi, la conversion du champ de commande en un contrôle de champ de modèle n'est pas une option, car le champ de commande est livré avec des fonctionnalités intégrées que je devrais sinon créer moi-même, par exemple le fait qu'il se transforme en "Mettre à jour Annuler" lorsque vous cliquez sur Modifier, et que lorsque vous cliquez sur Modifier, toutes les cellules de la ligne qui sont des étiquettes deviennent des zones de texte, etc.
Dans mon approche, vous pouvez laisser le champ de commande tel quel, puis vous pouvez le masquer au besoin via du code derrière. Dans cet exemple, je le cache si le champ "Scénario" de la grille affiche le texte "Réel" pour la ligne pertinente de l'événement RowDataBound.
protected void gridDetail_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (((Label)e.Row.FindControl("lblScenario")).Text == "Actual")
{
LinkButton cmdField= (LinkButton)e.Row.Cells[0].Controls[0];
cmdField.Visible = false;
}
}}
Si vous souhaitez supprimer complètement la colonne (c'est-à-dire pas seulement le bouton) du tableau, utilisez un gestionnaire d'événements approprié, par ex. pour l'événement OnDataBound
, puis masquez la colonne appropriée sur la cible GridView
. Choisissez un événement qui ne se déclenchera qu'une seule fois pour ce contrôle, c'est-à-dire pas OnRowDataBound
.
<asp:GridView ID="grdUsers" runat="server" DataSourceID="dsProjectUsers" OnDataBound="grdUsers_DataBound">
<Columns>
<asp:TemplateField HeaderText="Admin Actions">
<ItemTemplate><asp:Button ID="btnEdit" runat="server" text="Edit" /></ItemTemplate>
</asp:TemplateField>
<asp:BoundField DataField="FirstName" HeaderText="First Name" />
<asp:BoundField DataField="LastName" HeaderText="Last Name" />
<asp:BoundField DataField="Telephone" HeaderText="Telephone" />
</Columns>
</asp:GridView>
protected void grdUsers_DataBound(object sender, EventArgs e)
{
try
{
// in this case hiding the first col if not admin
if (!User.IsInRole(Constants.Role_Name_Admin))
grdUsers.Columns[0].Visible = false;
}
catch (Exception ex)
{
// deal with ex
}
}
<asp:GridView ID="gv_Document" CssClass="gridstyle" runat="server" OnRowDataBound="gv_Document_RowDataBound" AutoGenerateColumns="false" DataKeyNames="SourceGUID,Source,FilePath" ShowHeaderWhenEmpty="false" OnRowDeleting="gv_Document_RowDeleting">
<Columns>
<asp:BoundField HeaderText="ItemID" DataField="ItemID" ItemStyle-CssClass="hidden-field" HeaderStyle-CssClass="hidden-field" />
<asp:BoundField HeaderText="SourceGUID" DataField="SourceGUID" ItemStyle-CssClass="hidden-field" HeaderStyle-CssClass="hidden-field" />
<asp:BoundField HeaderText="Source" DataField="Source" ItemStyle-CssClass="hidden-field" HeaderStyle-CssClass="hidden-field" />
<asp:TemplateField HeaderText="">
<ItemTemplate>
<asp:HyperLink ID="hyperLink" runat="server" Target="_blank" NavigateUrl='<%# Bind("FilePath")%>'
Text='<%# Bind("FileName")%>'> </asp:HyperLink>
</ItemTemplate>
</asp:TemplateField>
<asp:BoundField HeaderText="Type" DataField="FileExtension" ItemStyle-CssClass="hidden-field" HeaderStyle-CssClass="hidden-field" />
<asp:BoundField HeaderText="Content type" DataField="FileMimeType" ItemStyle-CssClass="hidden-field" HeaderStyle-CssClass="hidden-field" />
<asp:BoundField HeaderText="File Path" DataField="FilePath" ItemStyle-CssClass="hidden-field" HeaderStyle-CssClass="hidden-field" />
<asp:CommandField ShowDeleteButton="True" DeleteText="Delete" />
</Columns>
Utilisez ce code pour désactiver le bouton Supprimer dans gridview à partir du code situé derrière.
protected void gv_Document_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
((LinkButton)e.Row.Cells[7].Controls[0]).Visible = false;
}
}
Convertissez le CommandField en TemplateField et définissez la propriété visible du bouton en fonction de la valeur du champ (vrai/faux)
<asp:Button ID="btnSelect"
runat="server" Text="Select"
Visible='<%# DataBinder.Eval(Container.DataItem,"IsLeaf") %>'/>
Pour contrôler conditionnellement la vue des champs Modèle/Commande, utilisez l'événement RowDataBound de Gridview, comme:
<asp:GridView ID="gv1" OnRowDataBound="gv1_RowDataBound"
runat="server" AutoGenerateColumns="False" DataKeyNames="Id" >
<Columns>
...
<asp:TemplateField HeaderText="Order Status"
HeaderStyle-HorizontalAlign="Center" ItemStyle-HorizontalAlign="Center">
<ItemTemplate>
<asp:Label ID="lblOrderStatus" runat="server"
Text='<%# Bind("OrderStatus") %>'></asp:Label>
</ItemTemplate>
<HeaderStyle HorizontalAlign="Center"></HeaderStyle>
<ItemStyle HorizontalAlign="Center"></ItemStyle>
</asp:TemplateField>
...
<asp:CommandField ShowSelectButton="True" SelectText="Select" />
</Columns>
</asp:GridView>
et suivants:
protected void gv1_RowDataBound(object sender, GridViewRowEventArgs e)
{
Label lblOrderStatus=(Label) e.Row.Cells[4].FindControl("lblOrderStatus");
if (lblOrderStatus.Text== "Ordered")
{
lblOrderStatus.ForeColor = System.Drawing.Color.DarkBlue;
LinkButton bt = (LinkButton)e.Row.Cells[5].Controls[0];
bt.Visible = false;
e.Row.BackColor = System.Drawing.Color.LightGray;
}
}
J'ai fait une chose très simple pour activer ou désactiver le bouton de commande. Ci-dessous ma grille
<asp:GridView ID="grdOrderProduct" runat="server" TabIndex="1" BackColor="White" BorderColor="#CEC9EF" CssClass="table table-striped dataTable table-bordered"
OnRowEditing="grdOrderProduct_RowEditing" OnRowUpdating="grdOrderProduct_RowUpdating" OnRowDeleting="grdOrderProduct_RowDeleting" OnRowDataBound="grdOrderProduct_RowDataBound"
Width="100%" CellPadding="3" CellSpacing="1" BorderWidth="0" AutoGenerateColumns="False">
<HeaderStyle />
<AlternatingRowStyle />
<Columns>
<asp:BoundField DataField="ProductSKU" ReadOnly="true" HeaderText="Product SKU" HeaderStyle-CssClass="headTb4" />
<asp:BoundField DataField="ProductName" ReadOnly="true" HeaderText="ProductName" HeaderStyle-CssClass="headTb4" />
<asp:BoundField DataField="QTY" HeaderText="QTY" HeaderStyle-CssClass="headTb4" />
<asp:BoundField DataField="Discount" HeaderText="Discount %" HeaderStyle-CssClass="headTb4" />
<asp:BoundField DataField="TPrice" HeaderText="MRP" ReadOnly="true" HeaderStyle-CssClass="headTb4" />
<asp:CommandField ShowEditButton="true" ButtonType="Image" EditImageUrl="~/Images/edit.png"
UpdateImageUrl="~/Images/gear.png" CancelText=" " HeaderStyle-CssClass="headTb4"
ShowDeleteButton="true" DeleteImageUrl="~/Images/delete.png"
HeaderText="Action" ItemStyle-HorizontalAlign="Center">
<HeaderStyle CssClass="headTb4" />
<ItemStyle HorizontalAlign="Center" />
</asp:CommandField>
</Columns>
<AlternatingRowStyle CssClass="odd" />
<PagerStyle HorizontalAlign="Center" VerticalAlign="Top" Wrap="False" />
Dans la méthode suivante, j'ai fait les changements
protected void grdOrderProduct_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
foreach (ImageButton button in e.Row.Cells[5].Controls.OfType<ImageButton>())
{
if (button.CommandName == "Delete")
{
button.Visible = false;
}
}
}
}
Si cela était basé sur des rôles, vous pouvez utiliser le panneau à vues multiples mais vous ne savez pas si vous pouvez faire de même avec une propriété de l'enregistrement.
Cependant, vous pouvez le faire via du code. Dans votre événement rowdatabound, vous pouvez masquer ou afficher le bouton qu'il contient.
Vous pouvez masquer un CommandField ou ButtonField en fonction de la position (index) dans GridView.
Par exemple, si votre CommandField est en première position (index = 0), vous pouvez le masquer en ajoutant le code suivant dans l'événement RowDataBound du GridView:
protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
((System.Web.UI.Control)e.Row.Cells[0].Controls[0]).Visible = false;
}
}