Les écrans de MercatorPenguin permettant la modification des données ne permettent qu'un seul paramétrage XAML par langue d'utilisateur. Dans certains cas, il pourrait être nécessaire de tenir compte, par exemple, de caractéristiques du profil de l'utilisateur, afin de déterminer sous quelle forme cet écran doit être visible. Il est possible d'agir sur le code XAML via le customizer associé à l'élément en cours d'édition dans MercatorPenguin.
L'exemple repris ci-dessous illustre quelques possibilités pour une fiche article. Le customizer est donc de type SigStock. Il implémente l'interface MercatorUi.ICustomizers.IXmlDocumentUpdaterWithContextInfo. L'objet de contexte sera du type suivant :
- pour une fiche de signalétique : MercatorUi.Sig.Tools.SigRecordDescriptor
- pour une action : MercatorUi.Engine.Crm.Tools.ActionDescriptor
- pour un document de la gestion commerciale : MercatorUi.Engine.Gescom.Tools.BillingDocDescriptor.
Il faut noter que la méthode xmlDocument.FindNodesRecursive fait partie de MercatorExtensions, ce qui impose la présence de la clause :
using MercatorExtensions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using MercatorApi;
using MercatorExtensions;
using MercatorUi;
using MercatorDatabase;
using System.Xml;
namespace SigStock
{
public class Customizer : MercatorUi.ICustomizers.IXmlDocumentUpdaterWithContextInfo
{
public void XmlDocumentUpdateWithContextInfo(XmlDocument xmlDocument, object contextInfo)
{
if (Globals.IsMercatorPenguinServer)
{
MercatorUi.Sig.Tools.SigRecordDescriptor sigRecordDescriptor = (MercatorUi.Sig.Tools.SigRecordDescriptor)contextInfo;
// supprimer un élément
XmlNode node = xmlDocument.FindNodesRecursive(n => (n.Name == "m:EditPicker") && (n.Attributes["Source"].Value == "s_modeled")).FirstOrDefault();
if (node != null)
node.ParentNode.RemoveChild(node);
// changer la couleur de fond d'un élément
node = xmlDocument.FindNodesRecursive(n => (n.Name == "m:EditEntry") && (n.Attributes["Source"].Value == "s_cle1")).FirstOrDefault();
if (node != null)
{
XmlAttribute attr = xmlDocument.CreateAttribute("BackgroundColor");
attr.Value = "Red";
node.Attributes.SetNamedItem(attr);
}
// disabler un élément
node = xmlDocument.FindNodesRecursive(n => (n.Name == "m:EditEntry") && (n.Attributes["Source"].Value == "s_cle2")).FirstOrDefault();
if (node != null)
{
XmlAttribute attr = xmlDocument.CreateAttribute("IsEnabled");
attr.Value = "false";
node.Attributes.SetNamedItem(attr);
}
// rendre un élément invisible
node = xmlDocument.FindNodesRecursive(n => (n.Name == "m:EditEntry") && (n.Attributes["Source"].Value == "s_cle3")).FirstOrDefault();
if (node != null)
{
XmlAttribute attr = xmlDocument.CreateAttribute("IsVisible");
attr.Value = "false";
node.Attributes.SetNamedItem(attr);
}
}
}
}
}
Ce code montre qu'il est simple d'agir sur du paramétrage XAML préexistant. Il est toutefois aussi possible de produire du contenu XAML programmatiquement dans le customizer. Dans le cas d'un signalétique, si on souhaite ajouter un EditEntry avec une source, il est nécessaire d'implémenter MercatorUi.ICustomizers.IStringUpdater ou MercatorUi.ICustomizers.IStringUpdaterWithContextInfo. En effet, par souci d'optimisation, MercatorPenguinServer ne sélectionne que les colonnes effectivement utilisées dans le code XAML avant sa modification par le customizer.
using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Linq;
using MercatorApi;
using MercatorExtensions;
using MercatorUi;
using MercatorDatabase;
using System.Xml;
namespace SigStock
{
public class Customizer : MercatorUi.ICustomizers.IXmlDocumentUpdaterWithContextInfo, MercatorUi.ICustomizers.IStringUpdaterWithContextInfo
{
public void XmlDocumentUpdateWithContextInfo(XmlDocument xmlDocument, object contextInfo)
{
if (Globals.IsMercatorPenguinServer)
{
// localiser le StackLayout principal
XmlNode parentStackLayout = xmlDocument.FindNodesRecursive(n => (n.Name == "StackLayout")).First();
// créer un StackLayout horizontal pour y placer 2 éléments
XmlNode newStackLayout = xmlDocument.CreateNode(XmlNodeType.Element, "StackLayout", null);
parentStackLayout.AppendChild(newStackLayout);
XmlAttribute attrHorizontal = xmlDocument.CreateAttribute("Orientation");
attrHorizontal.Value = "Horizontal";
newStackLayout.Attributes.SetNamedItem(attrHorizontal);
// créer un Label et l'ajouter au nouveau StackLayout
XmlNode label = xmlDocument.CreateNode(XmlNodeType.Element, "Label", null);
XmlAttribute attrText = xmlDocument.CreateAttribute("Text");
attrText.Value = "NL :";
label.Attributes.SetNamedItem(attrText);
XmlAttribute attrFont = xmlDocument.CreateAttribute("Font");
attrFont.Value = "Medium";
label.Attributes.SetNamedItem(attrFont);
XmlAttribute attrMargin = xmlDocument.CreateAttribute("Margin");
attrMargin.Value = "10,5,25,0";
label.Attributes.SetNamedItem(attrMargin);
XmlAttribute attrVerticalOptions = xmlDocument.CreateAttribute("VerticalOptions");
attrVerticalOptions.Value = "Center";
label.Attributes.SetNamedItem(attrVerticalOptions);
newStackLayout.AppendChild(label);
// créer un EditEntry et l'ajouter au nouveau StackLayout
XmlNode entry = xmlDocument.CreateNode(XmlNodeType.Element, "m", "EditEntry", "clr-namespace:MercatorPenguin.Controls.Edit;assembly=MercatorPenguin.dll");
XmlAttribute attrSource = xmlDocument.CreateAttribute("Source");
attrSource.Value = "s_modelen";
entry.Attributes.SetNamedItem(attrSource);
XmlAttribute attrHorizontalOptions = xmlDocument.CreateAttribute("HorizontalOptions");
attrHorizontalOptions.Value = "FillAndExpand";
entry.Attributes.SetNamedItem(attrHorizontalOptions);
MercatorUi.Sig.Sig sigStock = MercatorUi.Sig._SigsStatic.SigByModule(MercatorUi.Sig._SigEnum.STOCK);
XmlAttribute attrMaxLength = xmlDocument.CreateAttribute("MaxLength");
attrMaxLength.Value = sigStock.FieldList["S_MODELEN"].Length.ToString();
entry.Attributes.SetNamedItem(attrMaxLength);
newStackLayout.AppendChild(entry);
}
}
public string StringUpdate(string s, object contextInfo)
{
if (Globals.IsMercatorPenguinServer)
{
MercatorUi.Sig.Tools.SigRecordDescriptor sigRecordDescriptor = (MercatorUi.Sig.Tools.SigRecordDescriptor)contextInfo;
s = s.Replace(" from ", ",s_modelen from ");
}
return s;
}
}
}
Depuis la version 2.10.17 de MercatorPenguinServer, il est aussi possible d'agir sur le code Xaml de la ListViewCell des documents en écriture (2ème onglet).
Par exemple, si une ListViewCell contient ce code XAML
<StackLayout Orientation="Horizontal" HorizontalOptions="FillAndExpand">
<Label Text="Q=" FontSize="12" Margin="0,0,10,0" />
<Label Text="@Q:### ##0.00" FontSize="12" Margin="0,0,25,0" />
<Label Text="PU=" FontSize="12" Margin="0,0,10,0" />
<Label Text="@PU:### ##0.00" FontSize="12" Margin="0,0,25,0" />
<Label Text="%=" FontSize="12" Margin="0,0,10,0" />
<Label Text="@REMISE:##0.00" FontSize="12" Margin="0,0,25,0" HorizontalOptions="FillAndExpand" />
</StackLayout>
il sera possible masquer conditionnellement la remise avec ce customizer :
public void XmlDocumentUpdateWithContextInfo(XmlDocument xmlDocument, object contextInfo)
{
if (Globals.IsMercatorPenguinServer && (Globals.CurrentUserRecord...))
{
XmlNode node = xmlDocument.FindNodesRecursive(n => (n.Name == "Label") && (n.Attributes["Text"].Value == "@REMISE:##0.00")).FirstOrDefault();
if (node != null)
node.ParentNode.RemoveChild(node);
node = xmlDocument.FindNodesRecursive(n => (n.Name == "Label") && (n.Attributes["Text"].Value == "%=")).FirstOrDefault();
if (node != null)
node.ParentNode.RemoveChild(node);
}
}
Info technique : dans le XmlDocument passé à XmlDocumentUpdateWithContextInfo, un nœud XamlListViewCell est ajouté au nœud ContentPage. Il contient tout le code XAML de la ListViewCell.