Exemples de customizers agissant sur le paramétrage XAML des écrans de modification

0000002838     -      13/12/2022

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;

Zoom
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.

Zoom
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 :

Zoom
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.