Salut,
Je travaille depuis quelque temps avec le SPGridView et jusqu'à présent, je n'ai jamais trouvé de moyen d'afficher les options du menu de manière dynamique selon la valeur d'une ou plusieurs cellules de ligne. J'ai commencé à regarder le code client et j'ai trouvé un début de réponse.
L'image ci-dessous illustre ce que je veux faire, disons qu'on a une table avec deux lignes et deux colonnes
et je veux afficher "Option 1" seulement lorsque la valeur de la colonne 2 est égale à "Row 1 - Cell 2"....
Dans le cas présent, "Option 1" et "Option 2" doivent être affichées pour la première ligne et seulement "Option 2" pour la deuxième ligne.
Dans l'API, il y a deux moyens de restreindre la visibilité des options d'un menu de SPGridView.
- La première méthode consiste à attribuer un niveau de permission comme par exemple:
MenuItem.Permissions = SPBasePermissions.AddListItems;
mais ceci restreint la visibilité pour toutes les options toutes lignes confondues et en fonction d'une permission et non d'une valeur contextuelle d'une colonne de ligne.
- La deuxième méthode consiste à utiliser HiddenScript qui prend en paramètre "True" ou "False" pour cacher ou non une option du menu.
Si vous spécifiez "true" ou "false" dans votre code, l'option de menu sera visible ou non pour la liste entière, or ce n'est pas ce que nous souhaitons.
Nous voulons que "Option 1" soit visible seulement si la colonne 2 d'une ligne contient la valeur "Row 1 - Cell 2".
Pour ce faire, nous devons créer une fonction javascript qui retourne true ou false selon une valeur de votre choix. Cette fonction contextuelle s'appliquera seulement sur la ligne ciblée par le clic de souris.
Voici un début de réponse que j'ai pu trouver mais ce n'est certainement pas la panacée universelle car certainement peu portable et quelque peu "tordue" mais bon, je vous la livre quand même :)....
En examinant le code client généré par le SPGridView et son menu, j'ai pu identifier la manière de cibler l'élément qui fallait pour récupérer la valeur de(s) celllule(s) que je voulais comparer pour afficher ou non une option. Il existe peut-être déjà quelque part une fonction javascript Sharepoint qui fait ce que les miennes font et probablement mieux mais je ne les ai pas encore trouvées et je n'ai pas encore eu beaucoup le temps d'investiguer plus.
Voici donc ce que j'ai trouvé mais je le rappelle, ce n'est certainement pas meilleure méthode mais cela constitue au moins une piste
Créer les fonctions javascript
<script language='javascript'>
function GetColumnValue(Target,ColumnIndex)
{
if(Target)
{
if(Target.event.srcElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.tagName == 'TR')
{
return Target.event.srcElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.cells[ColumnIndex].innerText;
}
else
{
return Target.event.srcElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.cells[ColumnIndex].innerText;
}
}
}
function DisplayMenuItem(Target,ColumnIndex,ValueToCompare)
{
return (GetColumnValue(Target,ColumnIndex) != ValueToCompare)
}
</script>
La fonction GetColumnValue récupère le innerText de la cellule ciblée par la variable "ColumnIndex" de la ligne courante.
La fonction DisplayMenuItem retourne "true" ou "false" selon le résultat de la comparaison. Notez que HiddenScript cache l'option si la valeur retournée est "true" et l'affiche dans le cas contraire.
Appeler les fonctions javascript
Dans votre code, vous pouvez appeler ces fonctions comme ceci:
YourMenuItem.HiddenScript = "DisplayMenuItem(this,1,'Row 1 - Cell 2')";
Ceci compare la valeur de la 2ème cellule (index 1) à la valeur 'Row 1 - Cell 2' et affiche "Option 1" seulement si celles-ci sont égales.
Vous pouvez combiner plusieurs critères comme ceci:
YourMenuItem.HiddenScript = "if(DisplayMenuItem(this,0,'Row 1 - Cell 1') || DisplayMenuItem(this,0,'Row 1 - Cell 2')) true; else false;";
Dans ce cas, "Option 1" apparaîtra seulement si la valeur de la première colonne est "Row 1 - Cell 1" et celle de la 2ème est "Row 1 - Cell 2".
Le Code en entier
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.SharePoint;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using Microsoft.SharePoint.WebControls;
using System.Data;
namespace SPGridViewWp
{
public class Grid : System.Web.UI.WebControls.WebParts.WebPart
{
SPGridView SPGridViewExample = null;
const string SPGridViewExampleMenuID = "TheMenu";
/// <summary>
/// Client code to handle the SPGridView menu items. As stated in my blog this is certainly not the beset
/// way of doing that but it could be considered as a good start.
/// </summary>
/// <returns></returns>
private string ClientScript()
{
StringBuilder ClientCode = new StringBuilder();
ClientCode.Append("<script language='javascript'>");
ClientCode.Append("function GetColumnValue(Target,ColumnIndex)");
ClientCode.Append("{");
ClientCode.Append(" if(Target){");
ClientCode.Append(" if(Target.event.srcElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.tagName == 'TR')");
ClientCode.Append(" {");
ClientCode.Append(" return Target.event.srcElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.cells[ColumnIndex].innerText;");
ClientCode.Append(" }else");
ClientCode.Append(" {");
ClientCode.Append(" return Target.event.srcElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.parentElement.cells[ColumnIndex].innerText;");
ClientCode.Append(" }");
ClientCode.Append(" }");
ClientCode.Append("}");
ClientCode.Append("function DisplayMenuItem(Target,ColumnIndex,ValueToCompare)");
ClientCode.Append("{");
ClientCode.Append(" return (GetColumnValue(Target,ColumnIndex) != ValueToCompare);");
ClientCode.Append("}");
ClientCode.Append("</script>");
return ClientCode.ToString();
}
protected override void CreateChildControls()
{
try
{
//in a real context, isolate the function in a .js file
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "CustomMenuScript", ClientScript());
this.Controls.Clear();
//Building the datatable
DataTable SPGridViewData = new DataTable();
SPGridViewData.Columns.Add(new DataColumn("Column 1"));
SPGridViewData.Columns.Add(new DataColumn("Column 2"));
DataRow NewRow = SPGridViewData.NewRow();
NewRow["Column 1"] = "Row 1 - Column 1";
NewRow["Column 2"] = "Row 1 - Column 2";
SPGridViewData.Rows.Add(NewRow);
NewRow = SPGridViewData.NewRow();
NewRow["Column 1"] = "Row 2 - Column 1";
NewRow["Column 2"] = "Row 2 - Column 2";
SPGridViewData.Rows.Add(NewRow);
SPGridViewExample = new SPGridView();
SPGridViewExample.AutoGenerateColumns = false;
#region Menu Template
MenuTemplate SPGridViewExampleMenu = new MenuTemplate();
SPGridViewExampleMenu.ID = SPGridViewExampleMenuID;
MenuItemTemplate SPGridViewExampleMenuItem = new MenuItemTemplate("Option 1");
//HiddenScript call
SPGridViewExampleMenuItem.HiddenScript = "DisplayMenuItem(this,1,'Row 1 - Column 2')";
SPGridViewExampleMenu.Controls.Add(SPGridViewExampleMenuItem);
//No hidden script -> always visible
SPGridViewExampleMenuItem = new MenuItemTemplate("Option 2");
SPGridViewExampleMenu.Controls.Add(SPGridViewExampleMenuItem);
this.Controls.Add(SPGridViewExampleMenu);
SPMenuField Column1 = new SPMenuField();
Column1.HeaderText = "Column 1";
Column1.TextFields = "Column 1";
Column1.MenuTemplateId = SPGridViewExampleMenuID;
SPGridViewExample.Columns.Add(Column1);
#endregion
#region columns
SPBoundField Column2 = new SPBoundField();
Column2.HeaderText = "Column 2";
Column2.DataField = Column2.SortExpression = "Column 2";
SPGridViewExample.Columns.Add(Column2);
#endregion
SPGridViewExample.DataSource = SPGridViewData;
this.Controls.Add(SPGridViewExample);
SPGridViewExample.PagerTemplate = null;
SPGridViewExample.DataBind();
}
catch (Exception ex) { Context.Response.Write(ex.Message); }
}
}
}
Remarque
Cette technique ne fonctionne pour l'instant qu'avec Internet Explorer. Je n'ai pas encore généré le code client nécessaire pour gérer ça avec d'autres navigateurs (firefox notamment)
C'est donc une méthode à utiliser avec précaution ou selon un contexte bien précis. N'hésitez pas à poster des commentaires si vous connaissez d'autres moyens.