Extension de la synchronisation des données avec POS – option 2

Exportation sur POS

Il est possible de synchroniser les données non-associées aux objets créés dans POS et synchronisés avec le système ERP. À ces fins, il faut utiliser la procédure Synchronization.ExportCustoms. Il ne faut pas oublier que la structure dans le corps de la procédure <Customs><Custom> doit être conservée, mais la structure sous le nœud <Custom> peut être librement modifiée.

Il est souhaitable que la structure des tableaux à partir desquels nous sélectionnons les données à télécharger soit sous forme d’arbre et que le tableau principal contient les colonnes suivantes :

  • GUID – assure l’identification de l’objet entre POS et ERP
  • Id – à la relation dans la structure
  • Type – si nous voulons différencier les données sur DataService, d’autant plus s’il existe des extensions individuelles
  • WasSentToERP – pour filtrer les données qui ont déjà été envoyées

Marquer les données envoyées

Il est possible d’utiliser une méthode standarde du marquage des objets envoyés pour marquer les objets personnalisés.

À ces fins, nous surchargeons la méthode du service ISynchronizationRepository (cette zone n’a pas de points de branchement)

public class SynchronizationRepositoryExt : SynchronizationRepository
{
   public override void MarkIfWasSentToERP(string xml)
   {
      base.MarkIfWasSentToERP(xml);

      using (var context = new POSDBContext())
      {
         context.ExecuteProcedure("Synchronization.MarkSentCustomData", xml);
      }
   }
}

À l’intérieur, nous pouvons par exemple appeler une procédure qui marquera les objets envoyés.

CREATE PROCEDURE [Synchronization].[MarkSentCustomData]
    @p0 xml
AS
BEGIN
    UPDATE CustomSchema.CustomRootTable
    SET WasSentToERP = 1
    Where GUID in (SELECT xmlData.Col.value('@GUID','varchar(max)') FROM @p0.nodes('/Customs/Custom') xmlData(Col))
END
GO

Exemple d’exportation

CREATE PROCEDURE [Synchronization].[ExportCustoms] 
AS
BEGIN
    SET NOCOUNT ON;

    select
        pad.GUID 			as [@GUID],
        pad.Type as [@Type],
        pad.Data1 		as [@Data1],
        Synchronization.GetDatetimeString(pad.ChangeDate) 							as [@ChangeDate],
        (
            select			
td.Number 			as [@NumberString], 
td.Status	 			as [@Status], 
td.Value 				as [@Value]
            from 				CustomSchema.Table1 td 			where pad.Id = td.RootId
            for xml path('Table1'), root('Tables1'), type
        ),		
        (
            select				
ti.ToPayNet 				as [@ToPayNet], 
                ti.Points				 as [@Points], 
ti.ToPay				as [@ToPay]
            from 			CustomSchema.Table2 ti 			where 								pad.Id = ti.RootId
            for xml path('Table2'), root('Tables2'), type
        )

    from CustomSchema.RootData pad
    where pad.WasSentToERP = 0

    for xml path('Custom'), root('Customs')
    
END
GO

Importation du côté de DataService

L’importation des données se fait en utilisant le service IDataCustomService et en surchargeant la méthode SaveCustom. L’argument pour la méthode est chaque ligne Custom sous forme d’objet XElement.

Pour prendre en charge plusieurs extensions, il faut utiliser les points de branchement pour DataService.

Snippet pour l’importation

[DataServiceBusinessModule]
public static class Module    
{
   [MethodInitializer]
   public static void Initialize()        
   {
       var dataCustomService = IoC.Container.Resolve<IDataCustomExtensionPointService>();
       dataCustomService.OnSaveCustomEvent += DataCustomService_OnSaveCustomEvent;
   }
   private static void DataCustomService_OnSaveCustomEvent (object sender, XEEventArgs e)
   {
   //désérialisation + enregistrement des données
   }
}



Extension de la synchronisation des données avec POS – option 1

Exemple d’une procédure d’exportation

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Synchronization].[GetCustomData]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [Synchronization].[GetCustomData]
GO

CREATE FUNCTION [Synchronization].[GetCustomData]
(
    @syncType int,
    @documentId int
)
RETURNS XML
AS
BEGIN

    declare @data XML;
    
    set @data = (select [Implementations].[GetSpecificData](@syncType, @documentId)					
                    for xml path('SpecificElements'), root('CustomData'), type)
    return @data

END
GO

IF  EXISTS (SELECT * FROM sys.objects WHERE object_id = OBJECT_ID(N'[Implementations].[GetSpecificData]') AND type in (N'FN', N'IF', N'TF', N'FS', N'FT'))
DROP FUNCTION [Implementations].[GetSpecificData]
GO

CREATE FUNCTION [Implementations].[GetSpecificData]
(
    @syncType int,
    @documentId int
)
RETURNS XML
AS
BEGIN

    declare @specifics XML;

    
    set @specifics = (select 					
                    el.OrdinalNumber as [@OrdinalNumber],
el.SpecificCode		 as [@SpecificCode],
                    el. SpecificTypeId	 as [@SpecificTypeId]
                    from ExtensionSchema.SpecificDataTable el
                    inner join Documents.TradeDocuments doc on el.DocumentId = doc.Id
                    where el.DocumentId = @documentId and @syncType = 45 
                    for xml path('row'))
    return @specifics

END
GO

Exportation des données de POS

Il est possible d’ajouter des données personnalisées aux objets créés dans POS et synchronisés avec le système ERP. À ces fins, il faut remplacer la fonction Synchronization.GetCustomData dans la base POS. Cette fonction retourne XML et accepte le type d’objet synchronisé (int), ainsi que son identifiant (int) comme les arguments. Elle est démarrée séparément pour chaque objet qui doit être envoyé au système ERP.

Importation du côté de DataService

L’importation des données s’effectue dans le code C#. Chaque objet traité possède la propriété CustomData du type XElement. Les données doivent être désérialisées et traitées par l’utilisateur.

Les informations utiles peuvent être téléchargées de la classe statique WebServiceHelper. Il est possible d’obtenir les informations sur l’instance de POS pour chaque appel de la méthode du contrat de DataService :

– code de POS

– GUID de POS

– code de profile

– version

Exemple d’importation sur DataService

[DataServiceBusinessModule]
public static class Module    
{
   [MethodInitializer]
   public static void Initialize()        
   {
      var customerService = IoC.Container.Resolve<IDataCustomerExtensionPointService>();
      customerService.AfterSaveCustomerEvent += CustomerServiceEx_AfterSaveCustomerEvent;
   }
   private static void CustomerServiceEx_AfterSaveCustomerEvent(object sender, DTOResultEventArgs<Queue.DTO.CustomerDTO, string, int> e)         
   {
      Console.WriteLine("{0}: {1}", e.Argument, e.EntityRow.CustomData.Name);
      var xe = e.EntityRow.CustomData; // XElement
   }
}



Extensions de la synchronisation des données avec DataService

Ajouter et actualiser les données

Action du côte de Comarch ERP Standard

La base de Comarch ERP Standard contient la procédure POS.ExportCustomObjects. Cette fonction doit être remplacée de façon à ce qu’elle récupère les données qui doivent être envoyées à un point de vente particulier depuis la base de données et les renvoie au format XML.

Les paramètres ci-dessous sont passés à la procédure pour limiter et personnaliser l’ensemble des données envoyées à un point de vente POS particulier :

  • @rowVersion (bigint) – valeur permettant d’effectuer une synchronisation différentielle. C’est la valeur qui se trouve dans XML généré par cette procédure lors de la dernière synchronisation réussie (dans l’attribut RowVersion).
  • @companyUnitId (int) – Id de centre où un point de vente POS a été défini (CompanyStructure.CompanyUnits)
  • @pointOfSaleId (int) – Id de point de vente POS (Synchronization.PointsOfSales)
  • @languageId (int) – Id de langage de données (Dictionaries.Languages)

Lors de l’exportation des données des colonnes du type bit et datetime, il faut utiliser les fonctions POS.GetBitString et POS.GetDatetimeString.

Action du côté de POS

Dans la base POS existe la procédure Synchronization.ImportCustomObjects. Elle doit être remplacée de façon à ce qu’elle mette à jour les tableaux dans la base de données POS sur la base des données XML reçues de Comarch ERP Standard – celles générées par la procédure  POS.ExportCustomObjects.

Exemple

L’exemple présente la synchronisation différentielle des données de deux tableaux – l’exportation de la base Comarch ERP Standard et l’importation dans la base POS :

  • Dic_PaymentForms -> Configuration.CustomPaymentForms
  • Dic_Country -> Configuration.CustomCountries
a)     Procédure d’exportation
ALTER PROCEDURE [POS].[ExportCustomObjects]
    @rowVersion bigint,
    @companyUnitId int,
    @pointOfSaleId int,
    @languageId int
AS
BEGIN
                                    SET NOCOUNT ON;
    declare @dbts bigint = cast(@@DBTS as bigint)
        
    select
            @dbts as [@RowVersion],

        (select
            pf.Id			as [@Id],
            pf.Name		as [@Name],
            pf.CategoryId		as [@Type],
            POS.GetBitString(pf.Active)
                        as [@IsActive]
        from SecDictionaries.Dic_PaymentForms pf
        where pf.Timestamp > @rowVersion		
        for xml path('PaymentForm'), type),
        (select
                        c.Id		as [@Id],
            c.Code		as [@Code],
            c.Name		as [@Name],
            POS.GetBitString(c.Active)
                    as [@IsActive]
        from dbo.Dic_Country c
        where c.Timestamp > @rowVersion
        
        for xml path('Country'), type)
    for xml path('CustomObjects')
END

b) Procédure d’importation

ALTER PROCEDURE [Synchronization].[ImportCustomObjects]
    @XML xml
AS
BEGIN
    SET NOCOUNT ON;
    
    -- Countries --
    select
        doc.col.value('@Id', 'int') Id,
        doc.col.value('@Code', 'nvarchar(50)') Code,
        doc.col.value('@Name', 'nvarchar(100)') Name,
        doc.col.value('@IsActive', 'bit') IsActive
    into #Countries
    from @XML.nodes('/DataFromERP/CustomObjects/Country') doc(col)

update pos
    set
        Code = erp.Code,
        Name = erp.Name,
        IsActive = erp.IsActive
    from Configuration.CustomCountries pos
        join #Countries erp on erp.Id = pos.Id

    insert into Configuration.CustomCountries
    (
        Id,
        Code,
        Name,
        IsActive
    )
    select
        Id,
        Code,
        Name,
        IsActive
    from #Countries erp
    where not exists (select 1 from Configuration.CustomCountries where Id = erp.Id)

    -- Payment forms --
    select
        doc.col.value('@Id', 'int') Id,
        doc.col.value('@Name', 'nvarchar(50)') Name,
        doc.col.value('@Type', 'tinyint') [Type],
        doc.col.value('@IsActive', 'bit') IsActive
    into #PaymentForms
    from @XML.nodes('/DataFromERP/CustomObjects/PaymentForm')  doc(col)

    update pos
    set
        Name = erp.Name,
        Type = erp.Type,
        IsActive = erp.IsActive
    from Configuration.CustomPaymentForms pos
        join #PaymentForms erp on erp.Id = pos.Id

    insert into Configuration.CustomPaymentForms
    (
        Id,
        Name,
        Type,
        IsActive
    )
    select
        Id,
        Name,
        Type,
        IsActive
    from #PaymentForms erp
    where not exists (select 1 from Configuration.CustomPaymentForms where Id = erp.Id)
    
END

Gestion des répertoires universels

Mise à jour de la procédure d’exportation

Dans la clause WHERE de la procédure POS.ExportGenericDirectories il faut inclure InternalName de répertoire qui doit être également synchronisé.

Dans la clause WHERE de la procédure POS.ExportGenericDirectoryValues il faut inclure InternalName de répertoire qui doit être également synchronisé.

Clés étrangères pour le schéma Standard

Pour les tableaux synchronisés

La disponibilité des objets, les autorisations etc. peuvent, au niveau de la ligne d’un tableau donné, affecter les données qui seront synchronisées. Un exemple serait les Clients, groupes clients, entrepôts, registres, modes de paiement etc.

Afin d’éviter une évaluation multiple, il faut utiliser le tableau POS.SentObjects pour savoir quelles données doivent être synchronisées dans les tableaux dérivées (sur la base de FC).

Exemple : Exportation des définitions d’impôts associés à un client

(select
        ven.Id as [@Id],
        ven.ActivityId as [@ActivityId],
        ven.VendorId as [@VendorId]
        from Implementations.VendorActivityConnectionsEcoTax ven
        inner join Implementations.ActivityEcoTax ac on ven.ActivityId = ac.Id
        inner join Implementations.SettingsEcoTax sett on ac.Id = sett.CompanyActivityId and sett.CompanyId = @companyUnitId 
        inner join POS.SentObjects so on so.ObjectId = ven.VendorId and so.SyncTypeId = 14 and so.POSId = @pointOfSaleId
        where ven.Timestamp > @rowVersion 
                        for xml path('VendorActivityConnectionsEcoTax'), type)

La valeur du type d’objet synchronisé peut être consultée dans le tableau POS.SyncTypes.

Pour les tableaux non-synchronisés

L’utilisateur doit lui-même implémenter le processus de synchronisation, comme si le tableau provenait d’une extension.

Suppression des données

Actions du côté de Comarch ERP Standard

  1. Il faut ajouter dans le tableau DeletionTypes l’entrée avec « Id >= 1000 » et le nom unique du type des objets supprimés.
  2. Dans le déclencheur AFTER DELETE du tableau à partir duquel la suppression des données doit être synchronisée avec POS, ajoutez des entrées concernant les objets supprimés à la table POS.DeletedObjects. Colonnes à compléter :
    • DeletionTypeId – identifiant du type défini dans le point a)
    • Ident – identifiant d’objet supprimé. Un identifiant peut être un nombre (int), un GUID (uniqueidentifier), nvarchar ou un ensemble de valeurs séparées par le caractère « | », par exemple : „3428|654”. Voir aussi le point concernant les actions du côté de POS (colonnes IdentColumnName, IdentColumnType).
    • POSId – identifiant POS (Synchronization.PointsOfSales) – il faut le compléter, si l’objet doit être supprimé d’un point de vente POS particulier ou laisser NULL s’il doit être supprimé de tous les points de vente.

Actions du côte de POS

Ajoutez au tableau Synchronization.DeletionTypes une ligne définissant le moyen de gestion par le mécanisme de synchronisation d’information sur la suppression d’objets provenant d’ERP.

Il existe deux modes de suppression : automatique et personnalisé.

  • En mode automatique, le mécanisme de synchronisation supprimera automatiquement les données du tableau indiqué en identifiant les lignes à partir des noms des colonnes (les valeurs doivent être complétées dans les colonnes TableName, IdentColumnName, IdentColumnType, ainsi que la valeur NULL dans la colonne CustomProcName). Ce mode est utilisé pour supprimer dans POS presque tous les types d’objets supprimables dans l’ERP (voir les entrées standards dans le tableau Synchronization.DeletionTypes).
  • Le mode personnalisé exige que la procédure prenant en charge la suppression des objets du type donné (la colonne CustomProcName doit être complétée) soit indiquée. Ce mode est utilisé lorsque la condition de suppression est plus complèxe et il n’est pas possible d’appliquer le mécanisme automatiue ou lorsqu’il faut effectuer des opérations supplémentaires lors de la suppression.

Le tableau Synchronization.DeletionTypes contient les colonnes suivantes :

  • DelType – nom comme dans la base Standard dans le tableau DeletionTypes.
  • Order – nombre définissant l’ordre de suppression des types d’objets.
  • TableName [uniquement en mode automatique] – nom du tableau dont les objets doivent être automatiquement supprimés dans le cadre du type donné DelType.
  • IdentColumnName [uniquement en mode automatique] – noms des colonnes (séparés par le caractère « | ») selon lesquels se fait l’identification automatique des lignes supprimées, par exemple : „Id”, „GUID”, „PriceTypeId|CustomerGroupId”. Leur quantité et ordre doivent correspondre à la valeur saisie dans la base Standard dans la colonne POS.DeletedObjects.Ident.
  • IdentColumnType [uniquement en mode automatique] – types des colonnes définis comme IdentColumnName dans la même quantité et ordre, par exemple „int”, „uniqueidentifier”, „int|int”. Dans le cas de nvarchar(x), il faut saisir « nvarchar ».
  • CustomProcName [uniquement en mode personnalisé] – nom de procédure responsable pour la suppression des objets d’un type donné. Cette colonne doit utiliser les données du tableau temporaire #DeletedObjects. Voir les procédures existantes Synchronization.DeleteCustomerPriceTypes, Synchronization.DeleteWarehouseDocuments.



Gestion des exceptions

Chaque exception non réglée dans POS sera représentée sous forme d’une vue de message et enregistrée dans le fichier du journal d’événements. La fenêtre se compose du titre d’erreur et de son contenu. Si l’exception est du type System.Exception ou hérite de lui, le titre d’erreur sera le type d’exception et le contenu sera son Message. L’information enregistrée dans le journal d’événements contiendra le type d’exception, le contenu Message et la pile d’appel. Cette solution n’est pas trop douée, car l’utilisateur ne doit pas s’interroger quand il voit des titres bizarres comme : NullReferenceException.

Une meilleure solution est d’utiliser la classe Comarch.POS.Library.Erros.RetailException. Cette classe hérite de System.Exception et introduit deux propriétés supplémentaires qui sont par défaut prédéfinies. C’est la propriété UITitle utilisée à afficher le titre d’erreur et UIMessage utilisée à afficher le contenu plus adapté aux besoins de l’utilisateur. Le contenu est bien sûr localisé dans les langues pris en charge par POS. Comme dans le cas précédent, le type d’exception, son contenu original et la pile d’appel sont tous enregistrés dans le journal d’événements. Pour définir un titre et/ou un contenu personnalisé, il faut créer un nouveau type d’exception héritant de la classe RetailException et surcharger les propriétés appropriées.

Dans l’application POS est définie une dizaine des types dérivés du RetailException. Le tablau ci-dessus présente une liste exemplaire incomplète avec le contenu d’UITitle et UIMessage pour la langue polonaise.

Type d’exception UITitle UIMessage
RetailException Erreur système Une erreur inconnue s’est produite
RetailSecurityException Accès refusé Une erreur inconnue s’est produite
RetailVoucherException Gestion des bons d’achat Une erreur inconnue s’est produite
RetailVoucherBlockedException Gestion des bons d’achat Le bon d’achat {0} est bloqué.



Vérification des autorisations

Authentification d’utilisateur

Les utilisateurs POS sont authentifiés à l’aide du service ISecurityService. Il contient les méthodes permettant la connexion d’utilisateur au système, la déconnexion, le verrouillage de l’écran et la vérification si l’utilisateur a des autorisations requises.

Méthodes du service ISecurityService :

  • SignIn(string login, SecureString password)
    Cette méthode permet à l’utilisateur de se connecter au système.
  • SignOut()
    Cette méthode déconnecte l’utilisateur. En conséquence, toutes les vues ouvertes auparavant sont fermées et l’application revient à la vue de connexion.
  • Lock()
    Cette méthode bloque l’écran. Si elle est appelée, la vue de connexion est ouverte et il n’est pas possible d’afficher les autres vues ouvertes jusqu’à ce que l’identité de l’utilisateur ne soit vérifiée en fournissant le mot de passe.

Autorisation d’utilisateur

Chaque utilisateur connecté dans POS peut avoir ou ne pas avoir les autorisations aux endroits de l’application définis auparavant. Les autorisations sont définies dans le système ERP par le biais de l’attribution des autorisations aux actions et objets métiers à un groupe d’utilisateurs. Afin de vérifier si l’utilisateur connecté a des autorisations requises, il faut utiliser le service IAuthorizationService et sa méthode ValidatePermissions ou, si nous sommes dans la classe de ViewModel, appeler directement la méthode élargissant avec le même nom. Appeler la méthode fait vérifier les autorisations. Si la vérification échoue, l’application ouvre une vue modale où il est possible de sélectionner l’utilisateur pour lequel le processus de vérification sera relancé (à condition qu’un nom d’utilisateur et un mot de passe appropriés soient fournis). Ceci ne change pas l’utilisateur connecté, mais fait passer l’étape de vérification des autorisations. Paramètres de la méthode :

  • accessDeniedMessage (string) – texte qui doit apparaître lorsque l’utilisateur n’a pas d’autorisations vérifiées,
  • autorization (IAuthorization) – autorisation que nous voulons vérifier,
  • successAction (Action) – action qui doit être exécutée lorsque la vérification se termine avec succès,
  • cancelAction (Action) – action facultative qui doit être exécutée lorsque l’utilisateur annule la possibilité d’élever les autorisations en se connectant à un autre compte lors de la vérification des autorisations,
  • login (string) – nom d’utilisateur facultatif pour lequel les autorisations seront vérifiées,
  • password (SecureString) (par défaut null) – mot de passe de l’utilisateur pour lequel les autorisations seront vérifiées (requis si le nom d’utilisateur est saisi)
  • logByCard (bool) (par défaut false) – définit si l’utilisateur s’est connecté à l’aide d’une carte magnétique

Exemple :

Nous vérifions si l’utilisateur connecté est autorisé à ajouter un reçu :

this.ValidatePermissions(« Pas d'autorisations à émettre un reçu", Authorization.Check.To(PermissionName.Receipt).WithLevels(PermissionLevel.Add),
                () =>
                {
                    NotificationService.Show("Autorisations vérfiées avec succès", NotifyIcon.Information);
                });



Exemples

Une solution Visual Studio avec une liste complète des exemples divisés en projets séparés complète le sujet des extensions dans POS. Pour activer les exemples, vous pouvez construire toute la solution, copier les fichiers de résultat dans le dossier d’installation de POS et enregistrer un seul module initialisant POSUsageExample.dll (un guide d’enregistrement se trouve dans le fichier READEME.txt de la solution). Une alternative est de construire chaque projet avec une bibliothèque individuelle (en fonction de l’exemple que vous voulez analyser) et enregistrer uniquement cette bibliothèque dans l’application POS. Les projets sont divisés en trois catégories : exemples d’utilisation des contrôles, exemples des vues entières et exemples d’extension des vues existantes.

Exemples d’utilisation des contrôles POS

Exemple d’utilisation du contrôle ComboBox2

Exemples d’utilisation du contrôle avec une vue modale d’une liste de choix standard et avec une présentation personnalisée. Disponibles dans le projet ComboBox2Example.

Exemple d’utilisation du contrôle ButtonSpinner

Exemple d’utilisation du contrôle avec un TextBox pour contrôler les valeurs numériques saisies par l’utilisateur. Disponible dans le projet ButtonSpinnerExample.

Exemple d’utilisation du contrôle ComboBoxButton

Disponible dans le projet ComboBoxExample.

Exemple d’utilisation du contrôle MultiButton

Exemple d’utilisation du contrôle avec sa gestion complète dans l’application. Disponible dans le projet MultiButtonExample.

Exemple d’utilisation du contrôle ItemsContainer

Exemples d’utilisation du contrôle avec sa gestion complète dans l’application. Le premier avec une définition des éléments dans xaml et le second avec un contenu dynamique construit dans le code de manière asynchrone. Disponible dans le projet ItemsContainerExample.

Exemple d’utilisation du contrôle Grid

Exemple de construction d’une vue parfaitement gérable sur la base de Grid. Disponible dans le projet GridExample.

Exemple d’utilisation du contrôle FieldControl

Exemples d’utilisation du contrôle avec gestion complète et prise en charge de la validation. Disponible dans le projet FieldControlExample.

Exemple d’utilisation des contrôles TabControl et TabControlItem

Exemples d’utilisation des contrôles TabControl et TabControlItem pour créer des onglets sur une vue. Disponible dans le projet TabControlExample.

Exemple d’utilisation du contrôle DatePicker2

Un exemple d’utilisation du contrôle avec la validation se trouve dans le projet DatePicker2Example.

Exemples de la création des vues

Module simple avec une nouvelle vue vide

L’exemple montre comment créer des modules d’extension pour POS. Disponible dans le projet EmptyViewExample. Il comporte une classe Module permettant d’enregistrer le module et une vue vide (SimpleView, SimpleViewModel), ainsi que le mode de gestion de l’interface (DesignSimpleViewModel). La vue a été enregistrée sous forme d’une mosaïque dans le menu principal de l’application POS.

Vue typique de liste des ventes

L’exemple montre comment construire une vue typique avec une liste téléchargeant des données de manière asynchrone, prenant en charge le tri et la pagination, avec un moteur de recherche et des filtres. Cette vue contient une classe Module (responsable pour l’enregistrement du module d’extension et de la vue sous forme d’une mosaïque dans le menu principal de l’application POS), des classes de la vue et du viewmodel de la liste – SimpleListView, SimpleListViewModel i DesignSimpleListViewModel. Exemple disponible dans le projet DataGridCompleteExample.

Vue typique de document commercial

L’exemple montre comment construire une vue typique de document commercial contenant un DataGrid et un moteur de recherche SearchBox. Disponible dans le projet DocumentExample.

Vue d’un document commercial avec la gestion des attributs

Un exemple de construction de la vue de document commercial enrichi de la gestion des attributs pour la liste et sous forme des contrôles générés dynamiquement dans le conteneur de vue. Disponible dans le projet DocumentAttributesExample.

Exemples d’extensions des vues existantes dans POS

Ajouter un contrôle au conteneur de vue existante

Le projet ControlExtensionsExamples contient un exemple présenté dans ce document et un autre qui montre comment ajouter des boutons au conteneur ItemsContainer, ainsi que sur le Grid de la vue existante créée dans le même projet.

Ajouter une colonne DataGrid sur une vue existante

L’exemple complet de l’extension des colonnes de DataGrid a été présenté dans le projet DataGridColumnExtensionExample.

Exemple d’implémentation du moyen d’agrégation de données personnalisé dans DataGrid

Une implémentation exemplaire d’agrégation sous forme d’une médiane a été présentée dans le projet DataGridAggregationExample.

Exemple d’extension d’une zone de statut

Le projet StartBarExtensionExample ajoute deux boutons à la zone de statut. Un qui est un raccourci pour ouvrir un nouveau document commercial et l’autre utilisant le contrôle ComboBoxButton.




Extensions de la gestion d’interface

Les options d’extensibilité dont nous avons parlées jusqu’à présent concernent uniquement les contrôles intérieurs de POS. En cas de nécessité d’ajouter un nouveau contrôle gérable, nous pouvons utiliser le mécanisme d’extensibilité de la gestion d’interface. Ce mécanisme permet d’enregistrer de nouveaux types de contrôles et de définir lesquelles de propriétés seront gérables. À part de cela, il est également possible de rendre gérables les propriétés des contrôles existants et de masquer la gestion des propriétés sélectionnées.

Masquer les propriétés pour édition

Si une propriété est masquée, elle est supprimée de la gestion d’interface. L’utilisateur ayant accès à la gestion d’interface ne pourra pas modifier sa valeur. La valeur du contrôle dont la propriété sera masquée sera définie par défaut pour la valeur définie dans les styles. Pourtant, si la valeur par défaut a été définie dans le fichier ModernUI.xaml, elle sera ignorée (les différences dans la définition des valeurs par défaut ont été décrites dans le chapitre Définir les valeurs par défaut des propriétés gérables dans l’article Gestion de vues et de ses éléments).

Nous pouvons masquer des propriétés spécifiques sur un contrôle spécifique identifié de manière unique par son Layout Id. La méthode à masquer les propriétés est la méthode DisablePropertiesForLayoutElement dans la classe PropertiesManager. Paramètres de cette méthode :

  • layoutId (string) – paramètre qui est l’identifiant du contrôle dont la propriété on veut masquer.
  • properties (params DependencyProperty[]) – une ou plusieurs propriétés qui seront masquées pour un contrôle donné.

Exemple du masquage de la propriété Icône (ImageKey) de la mosaïque Nouvelle vente (layout id NewSalesDocument) :

PropertiesManager.Instance.DisablePropertiesForLayoutElement("NewSalesDocument", TileButton.ImageKeyProperty);

Attention
Dans le cas présenté ci-dessus, l’icône disparaîtra de la mosaïque Nouvelle vente, car la valeur par défaut de la propriété ImageKey a été définie dans le fichier ModernUI.xaml.

Exemple du masquage de la propriété Hauteur (Height) du bouton Valider (AcceptButton) de la configuration globale :

PropertiesManager.Instance.DisablePropertiesForLayoutElement("AcceptButton", FrameworkElement.HeightProperty);

Ajouter des nouvelles propriétés à modifier

Dans le cas où un contrôle existant ou un tout neuf contrôle a des propriétés personnalisées définies et nous voulons qu’elles soient gérables dans la gestion d’interface, il faut les enregistrer. Cela peut se faire de deux manières, selon que la propriété doit être visible uniquement pour un contrôle à un endroit spécifique ou globalement pour toutes les occurrences de ce contrôle.

Dans le premier cas (enregistrement visible uniquement pour un contrôle à un endroit spécifique), il faut utiliser la méthode AddPropertiesForLayoutElement de la classe PropertiesManager. Paramètres de la méthode :

  • layoutId (string) – identifiant unique de contrôle (Layout Id),
  • properties (params DependencyProperty[]) – propriétés de contrôle qui seront gérables

Dans le second cas (enregistrement visible globalement pour toutes les occurrences de contrôle), il faut utiliser la méthode RegisterControlProperties de la classe PropertiesManager. Paramètres de la méthode :

  • controlType (Type) – type de contrôle,
  • properties (params DependencyProperty[]) – propriétés qui seront visible pour le contrôle du type indiqué
  • baseTypeProperties (Type) – type de contrôle de base à partir de laquelle seront téléchargées les propriétés enregistrées auparavant et utilisées à enregistrer les propriétés de ce contrôle

Gestion des attributs

L’application POS prend en charge les attributs à valeur unique synchronisés à partir du système ERP. Types d’attributs pris en charge : texte, nombre, répertoire, valeur logique, liste, date. Pour que la classe d’attribut donnée soit synchronisée vers un point de vente POS, elle doit être marquée dans le système ERP (Standard) à afficher et/ou à modifier dans la section Retail POS. Les attributs peuvent être affichés sous forme des colonnes dans la liste (contrôle datagrid) ou sous forme des contrôles (générés en fonction du type de classe d’attribut, par exemple pour la classe du type texte ça sera le TextBox, alors que pour le type répertoire ça sera le ComboBox).

Ajouter une nouvelle classe d’attribut à une vue existante dans POS

Dans l’application POS, chaque vue qui prend en charge les attributs est directement associé à un objet du système ERP. Par exemple, la vue Liste des clients affiche les attributs dans la liste sous forme des colonnes. Il est possible d’afficher les attributs avec leurs valeurs attribuées uniquement à l’objet Client dans le système ERP. Dans le cas de la vue du reçu, la liste (datagrid) affiche les classes d’attributs associées uniquement à l’objet Élément de reçu (REC), alors que les attributs affichés dans le coin inférieur droit sous forme des contrôles sont associés à l’objet Reçu (REC).

Liste des vues prenant en charge l’attribut avec les objets du système ERP associés

Vue POS Élément de vue Entité métier dans le système ERP
Nouvelle vente

(DocumentView)

Liste des positions Élément du reçu (REC)
Document Reçu (REC)
Aperçu du reçu

(DocumentPreviewView)

Liste des positions Élément du reçu (REC)
Document Reçu (REC)
Attributs du reçu (vente rapide)

(DocumentAttributesView)

Document Reçu (REC)
Détails de position dans le reçu (vente rapide)

(DocumentItemPropertiesView)

Document Élément du reçu (REC)
Facture

(DocumentView)

Liste des positions Élément de la facture client (FC)
Document Facture client (FC)
Aperçu de la facture

(DocumentPreviewView)

Liste des positions Élément de la facture client (FC)
Document Facture client (FC)
Attributs de la facture (vente rapide)

(DocumentAttributesView)

Document Facture client (FC)
Détails de position dans la facture (vente rapide)

(DocumentItemPropertiesView)

Document Élément de la facture client (FC)
Correctif manuel du reçu

Correctif manuel de la quantité du reçu – échange

(ManualExchangeView)

Liste des positions Élément du correctif manuel de la quantité du reçu (CQR)
Document Correctif manuel de la quantité du reçu (CQR)
Aperçu du correctif manuel de la quantité du reçu

(ManualCorrectionPreviewView)

Liste des positions Élément du correctif manuel de la quantité du reçu (CQR)
Document Correctif manuel de la quantité du reçu (CQR)
Correctif manuel de la quantité de la facture

Correctif manuel de la quantité de la facture – échange

(ManualExchangeView)

Liste des positions Élément du correctif manuel de la quantité de la facture (CQFC)
Document Correctif manuel de la quantité de la facture (CQFC)
Aperçu du correctif manuel de la quantité de la facture

(ManualCorrectionPreviewView)

Liste des positions Élément du correctif manuel de la quantité de la facture (CQFC)
Document Correctif manuel de la quantité de la facture (CQFC)
Correctif du reçu

(ExchangeView)

Liste des positions Élément du correctif de la quantité du reçu
Document Correctif de la quantité du reçu
Aperçu du correctif du reçu

(CorrectionPreviewView)

Liste des positions Élément du correctif de la quantité du reçu
Document Correctif de la quantité du reçu
Correctif de la facture

(ExchangeView)

Liste des positions Élément du correctif de la quantité de la facture
Document Correctif de la quantité de la facture
Aperçu du correctif de la facture

(CorrectionPreviewView)

Liste des positions Élément du correctif de la quantité de la facture (CQFC)
Document Correctif de la quantité de la facture (CQFC)
Facture d’acompte

(AdvanceInvoiceView)

Document Facture d’acompte
Aperçu de la facture d’acompte

(AdvanceInvoicePreviewView)

Document Facture d’acompte
Correctif de la facture d’acompte

(AdvanceInvoiceCorrectionView)

Document Correctif de la facture d’acompte
Aperçu du correctif de la facture d’acompte

(AdvanceInvoiceCorrectionPreviewView)

Document Correctif de la facture d’acompte
Bordereau de détaxe

(TaxFreeView)

Liste des positions Élément du bordereau de détaxe (BD)
Document Bordereau de détaxe (BD)
Aperçu du bordereau de détaxe

(TaxFreePreviewView)

Liste des positions Élément du bordereau de détaxe (BD)
Document Bordereau de détaxe (BD)
Liste des ventes

(DocumentsListView)

Liste des positions Reçu (REC), Facture client (FC), Facture d’acompte, Correctif de la quantité du reçu (CQR), Correctif de la quantité de la facture (CQFC), Correctif manuel de la quantité du reçu (CQR), Correctif manuel de la quantité de la facture (CQFC), Correctif de la facture d’acompte, Bordereau de détaxe (BD)
Clients

(CustomesListView)

Liste des positions Client
Ajouter/Modifier le particulier

(CustomerView)

Document Client
Ajouter/Modifier le professionnel

(BusinessCustomerView)

Document Client
Détails du client

(CustomerDetailsView)

Document Client
Détails du professionnel

(BusinessCustomerDetailsView)

Document Client
Nouvelle commande

(SalesOrderView)

Liste des positions Élément de la commande client (COMC)
Document Commande client (COMC)
Aperçu de la commande client

(SalesOrderPreviewView)

Liste des positions Élément de la commande client (COMC)
Document Commande client (COMC)
Préparation de la commande

(SalesOrderPreparationView)

Liste des positions Élément de la commande client (COMC)
Nouveau devis

(SalesQuoteView)

Liste des positions Élément de la commande client (DC)
Document Commande client (DC)
Aperçu du devis client

(SalesQuotePreviewView)

Liste des positions Élément de la commande client (DC)
Document Commande client (DC)
Commandes et devis client

(SalesOrdersListView)

Liste des positions Commande client (COMC), Devis client (DC)
Réclamation

(ComplaintView)

Liste des positions Élément de la réclamation de vente (REVC)
Document Réclamation de vente (REVC)
Réclamations

(ComplaintsListView)

Liste des positions Réclamation de vente (REVC)
Document de caisse (DC/RC)

(CashDocumentView)

Document Transaction caisse/banque
Dépôt/Retrait Coffre-fort

(VaultInflowOutflowView)

Document Transaction caisse/banque
Documents de caisse

(CashDocumentsListView)

Liste des positions Transaction caisse/banque
Aperçu du document de sortie de stock ME-

(WarehouseDocumentPreviewView)

Liste des positions Élément du mouvement d’entrepôt (ME-)
Document Mouvement d’entrepôt (ME-)
Nouveau document de sortie du stock

(NewWarehouseDocumentView)

Liste des positions Élément du mouvement d’entrepôt (ME-)
Document Mouvement d’entrepôt (ME-)
Document de sortie du stock

(WarehouseDocumentView)

Liste des positions Élément du mouvement d’entrepôt (ME-)
Document Mouvement d’entrepôt (ME-)
Document de réception PRR

(ReceivingAndDeliveryReportView)

Document Protocole de réception (PRR)
Documents d’entrepôt

(WarehouseDocumentsListView)

Liste des positions Mouvement d’entrepôt (ME-), Protocole de réception (PRR), Commande fournisseur (COMF), Bon de réception (REC)
Réception d’un bordereau d’expédition

(DeliveryNoteView)

Document Réception d’un bordereau d’expédition
Aperçu du bordereau d’expédition

(DeliveryNotePreviewView)

Document Réception d’un bordereau d’expédition
Réception de la livraison ME-

(WarehouseDocumentsToReceiptListView)

Liste des positions Mouvement d’entrepôt (ME-), Protocole de réception (PRR), Commande fournisseur (COMF), Bon de réception (REC)
Bon de réception

(PurchaseOrderReceptionView)

Liste des positions Élément du bon de réception (REC)
Document Bon de réception (REC)
Commande fournisseur

(PurchaseOrderView)

Liste des positions Élément de la commande fournisseur (COMF)
Document Commande fournisseur (COMF)
Correctifs des ressources

(StockCorrectionsListView)

Liste des positions Profit (PROF), Perte (PERT)
Profit/Perte

(NewInternalReceiptOrReleaseView)

Liste des positions Elément du profit (PROF), élément de la perte (PERT)
Document Profit (PROF), Perte (PERT)
Aperçu du Profit/ de la Perte

(InternalReceiptOrReleasePreviewView)

Liste des positions Elément du profit (PROF), élément de la perte (PERT)
Document Profit (PROF), Perte (PERT)
Commande interne

(InternalOrdersListView)

Liste des positions Commande interne (COMI)
Nouveau colis

(GeneratedWarehouseDocumentView)

Liste des positions Elément du mouvement d’entrepôt (ME-)
Document Mouvement d’entrepôt (ME-)
Transferts manuels

(ManualMovementsListView)

Liste des positions Elément du mouvement d’entrepôt (ME-)
Transfert manuel

(NewManualMovementWarehouseDocumentView)

Liste des positions Elément du mouvement d’entrepôt (ME-)
Document Mouvement d’entrepôt (ME-)
Mouvements internes

(InternalMovementsListView)

Liste des positions Elément du mouvement d’entrepôt (ME-)
Mouvement interne

(NewInternalWarehouseDocumentView)

Liste des positions Mouvement d’entrepôt (ME-)
Inventaire

(InventoryCountView)

Document Inventaire
Liste de comptage

(InventoryCountListView)

Document Liste de comptage
Commande interne créée

(CreatedInternalOrdersListView)

Liste des positions Commande interne (COMI)
Nouvelle commande interne

(NewInternalOrderView)

Document Commande interne (COMI)
Aperçu de la commande interne

(CreatedInternalOrderPreviewView)

Document Commande interne (COMI)
Liste des articles Liste des positions Article

 

Pour ajouter à POS la classe d’attribut sélectionnée, il faut la marquer comme Retail POS (aperçu et/ou modification). L’option d’aperçu permettra à l’attribut de fonctionner en mode lecture seule dans l’application POS. En revanche, si l’option modification est sélectionnée, la valeur de l’attribut pourra être modifiée et après l’enregistrement cette information sera transférée au système ERP. Ensuite, il faut lier la classe d’attribut avec le type d’objet approprié qui est pris en charge par POS (voir le tableau ci-dessus). Après avoir ajouté et synchronisé les réglages, les nouveaux attributs apparaîtront dans l’application POS sur la vue appropriée et l’utilisateur POS pourra les gérer à partir du niveau de la configuration d’interface.

Par exemple, nous ajoutons une nouvelle classe d’attribut X qui est du type texte et nous la marquons comme modifiable dans la rubrique Retail POS. Ensuite, nous la lions avec l’objet Client dans le système ERP. Après la synchronisation des données, nous démarrons l’application POS et nous ouvrons la configuration de la vue Ajouter un client. Dans la configuration, nous cochons le conteneur approprié (CustomerItemsContainer) qui permet l’affichage des attributs. Ensuite, il faut sélectionner dans la liste disponible à droite le nouvel attribut X et le faire glisser dans l’endroit souhaité sur la vue.

Ajouter une nouvelle classe d’attribut à la nouvelle vue qui ne la prend pas en charge

La prise en charge des attributs peut être également ajoutée aux vues personnalisées créées dans le cadre de l’extension. Les attributs peuvent être affichés sous forme des colonnes générées dynamiquement dans la liste (contrôle DataGrid) ou sous forme des contrôles indépendants (le type de contrôle sera différent en fonction du type de classe d’attribut).

Attributs sous forme des colonnes dans la liste DataGrid

Afin d’implémenter dans les listes les attributs sous forme des colonnes générées dynamiquement, il faut dans un premier temps implémenter l’interface IAttributable pour l’entité de données. Cette interface fournit trois propriétés indispensables à la prise en charge correcte des attributs dans les listes. Les deux premières propriétés : Id et ObjectType doit être définies conformément à l’entité. L’Id est l’identifiant de l’entité et ObjectType est le type d’entité. La troisième propriété Attributes est un répertoire qui doit être rempli lors du téléchargement asynchrone des données pour la liste. Pour remplir ce répertoire, il faut utiliser la méthode FillAttributesForList qui est dans le service IAttributesService. Avant de pouvoir afficher les données du répertoire, la liste doit d’abord générer des colonnes supplémentaires. Pour que cela soit possible, lors du premier téléchargement des données (IsInitialization=true) il faut définir la propriété AttributeClasses dans la classe AsyncDataGridCollection. Pour définir cette propriété il faut utiliser la méthode GetAttributesClasses du service IAttributesService. Cette méthode adopte deux paramètres : le premier permet de définir quelles classes d’attributs doivent être affichées sur une liste donnée et le second filtre quelles classes seront visibles pour des groupes donnés. Dans le cas où le second paramètre est null, toutes les classes des groupes sélectionnés dans le premier paramètre sont téléchargées. L’implémentation doit être réalisée d’une façon qui permet la gestion du filtrage des classes d’attributs en mode design de vue. De ce fait, cette méthode doit être appelée dans le DesignViewModel d’une vue donnée avec le second paramètre définit sur null. Ceci permet de télécharger toutes les classes et de générer toutes les colonnes possibles (cachées par défaut). En revanche, dans le ViewModel de la vue, il faut transmettre au second paramètre la propriété VisibileAttributesClassesList qui contiendra une liste des classes d’attributs définie en mode design par l’utilisateur. Dans le cas de la méthode FillAttributesForList qui remplit le répertoire Attributes, il faut transmettre deux paramètres. Le premier c’est une liste des entités (une entité doit implémenter IAttribuable) et le second c’est une liste des identifiants des classes d’attributs dans laquelle il faut compléter chaque entité avec les valeurs de ces classes d’attributs. Aux fins d’optimisation et pour ne pas télécharger trop d’informations, le second paramètre est défini en transmettant la propriété VisibleAttributesClassesList.

Le tri des colonnes qui ont été générées pour les attributs n’est pas activé.

Les colonnes générées pour les attributs sont par défaut cachées. Afin de les afficher, il faut implémenter en mode design le téléchargement de tous les attributs possibles pour une liste donnée, pour que l’utilisateur puisse sélectionner cette colonne et définir sa visibilité, ainsi que ses autres propriétés.

Dans le cas où la liste est en mode lecture seule, les attributs sont affichés sous forme de texte. En revanche, en mode d’édition les attributs sont générés sous forme des contrôles appropriés, en fonction du type de données. Pour un type logique ça sera le CheckBox, pour une liste et pour un répertoire le ComboBox et pour les autres types le TextBox.

Un exemple complet d’implémentation peut être consulté dans le chapitre Vue d’un document commercial avec la gestion des attributs dans l’article Exemples.

Attributs comme contrôles indépendants

Une façon alternative d’affichage des attributs dans les vues créées est de les implémenter sous forme des contrôles dynamiquement générés qui dépend du type de classe d’attribut. Ces contrôles permettent également de modifier les valeurs des attributs. Leur implémentation est composée de trois étapes. La première étape consiste à télécharger les attributs et les afficher sous forme de contrôles visibles dans le conteneur défini. La seconde à implémenter la validation des valeurs dans les attributs. La troisième étape c’est l’enregistrement des modifications apportées aux valeurs des attributs. Un exemple complet d’implémentation peut être consulté dans le chapitre Vue d’un document commercial avec la gestion des attributs dans l’article Exemples.




Extensions des vues existantes

Des éléments supplémentaires peuvent être ajoutés à tout vue existante dans POS. Une extension peut être l’ajout d’une nouvelle colonne au datagrid, la suppression d’une colonne existante ou l’ajout d’un n’importe quel contrôle dans l’espace préparé auparavant. Il est également possible d’appeler les logiciels des entreprises tierces en ajoutant simplement le contrôle du bouton sous lequel sera caché la logique initialisant un autre processus.

Ajouter un nouvel élément au conteneur existant

Grâce aux extensions, il est possible d’ajouter tout contrôle à la vue existante sélectionnée, mais uniquement dans les lieux préparés auparavant. Il n’y a pas de limite du nombre des éléments ajoutés, mais ils ne peuvent être placés que dans les conteneurs préparés à l’extension (ItemsContainer et Grid).

Afin d’ajouter un contrôle à la vue existante, il faut commencer par déterminer si la vue est gérable et si elle contient le conteneur approprié où il sera possible de placer le nouvel élément. À ces fins, il faut ouvrir dans l’application POS la vue de la gestion d’interface. Ensuite, sélectionner de la liste des vues déroulante la vue pour laquelle nous allons créer une extension. Ensuite, il faut appuyer sur la barre Éléments et sélectionner à partir de la liste des conteneurs déroulante dans quel endroit de vue sera placé nouvel élément. Après avoir sélectionné un conteneur, il faut enregistrer son nom, car c’est un identifiant global qui sera indispensable à l’étape suivante de la création d’extension.

Si, lors de la création de notre propre vue, nous souhaitons la rendre extensible, il faut préparer l’espace pour cette éventualité en ajoutant un ou plusieurs contrôles de conteneur ou en construisant la vue à l’aide du contrôle Grid (Comarch.POS.Presentation.Core.Controls), en n’oubliant pas de leur donner des identifiants LayoutId uniques (pour plus de détails, voir l’article Gestion de vue et de ses éléments).

Pour ajouter un contrôle à la vue, il faut d’abord créer un nouveau module (voir le chapitre Nouveau module dans l’article Créer des vues) ou, s’il a déjà été créé, il faut aller au corps de la méthode Initialize() dans la classe Module. Afin d’étendre la vue avec un nouveau contrôle, il faut utiliser la méthode

AddButtonToContainer en cas d’ajout de bouton ou

AddElementToContainer<TFrameworkElement> – en cas d’ajout de tout contrôle du type FrameworkElement

Les paramètres requis pour les deux méthodes sont :

  • containerLayoutId (string) – identifiant du conteneur auquel sera ajouté un contrôle,
  • buttonLayoutId / elementLayoutId (string) – identifiant unique du nouveau contrôle (chaque contrôle doit avoir dans le conteneur un identifiant unique),
  • styleKey (string) – nom de clé facultatif dans le fichier ModernUI.xaml où sera défini le style du contrôle
  • buttonViewModelFunc / elementViewModelFunc (Func<IViewModel, FrameworkElementViewModel>) – paramètre facultatif permettant de créer un ViewModel local pour le contrôle. Dans le ViewModel nous pourrons définir la logique avec laquelle le contrôle pourra se binder (à l’aide de style).

Par analogie, pour ajouter un élément au Grid, il faut appeler :

AddElementToGrid<TFrameworkElement> – les paramètres sont les mêmes que pour les éléments ajoutés à un conteneur

Exemple :

Nous voulons ajouter à la vue du reçu un bouton qui, lorsqu’il sera cliqué, fait afficher une notification avec la valeur du document.

Le nom du conteneur auquel le bouton sera ajouté est DocumentViewRightButtonsContainer. Dans la classe Module du nouveau module d’extension, dans la méthode Initialize, nous ajoutons la ligne :

AddButtonToContainer("DocumentViewRightButtonsContainer", "ExtensionButton1", "ButtonStyle", ButtonViewModelFunc);

où l’ExtensionButton1 est le nom unique (identifiant LayoutId) du nouveau bouton, le ButtonStyle est le nom de la clé avec le style pour ce bouton et le ButtonViewModelFunc est la méthode qui retourne le ViewModel local où sera implémentée la logique appelant la notification avec le contenu approprié.

private FrameworkElementViewModel ButtonViewModelFunc(IViewModel viewModel)
{
    return new ButtonViewModel(viewModel, ViewManager, Container);
}
 
public class ButtonViewModel : FrameworkElementViewModel
{
    public DelegateCommand ExtensionButtonCommand { get; set; }
 
    private readonly IDocumentViewModel _documentViewModel;
    private readonly INotificationService _notifyService;
 
    public ButtonViewModel(IViewModel viewModel, IViewManager viewManager, IUnityContainer container) : base(viewModel, viewManager)
    {
        if (viewModel.IsDesignMode)
            return;

        _notifyService = container.Resolve<INotificationService>();
        _documentViewModel = (DocumentViewModel)viewModel;
        ExtensionButtonCommand=new DelegateCommand(ExtensionButtonAction);
    }
 
    private void ExtensionButtonAction()
    {
        _notifyService.Show($"Montant de document : {_documentViewModel.Document.Value}", NotifyIcon.Information);                
    }
}

Dans le fichier ModernUI.xaml de notre module, nous ajoutons le style pour le nouveau bouton en y définissant le contenu du bouton et nous relions l’action de clic à la commande associée à la méthode ExtensionButtonAction.

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:buttons="clr-namespace:Comarch.POS.Presentation.Core.Controls.Buttons;assembly=Comarch.POS.Presentation.Core">

<Style x:Key="ButtonStyle" TargetType="buttons:Button"
       BasedOn="{StaticResource {x:Type buttons:Button}}">
    <Setter Property="Content" Value="Pokaż wartość" />
    <Setter Property="Command" Value="{Binding ExtensionButtonCommand}" />
</Style>

Le code entier de l’exemple est disponible dans le chapitre Ajouter un contrôle au conteneur d’une vue existante dans l’article Exemples.

Ajouter une colonne à un DataGrid existant

La façon la plus simple d’ajouter une nouvelle colonne à un datagrid existant de la vue de document (par exemple du reçu/de la facture, de la commande client etc.) est assigner dans le système ERP un attribut à un élément de document (pour plus de détails, voir l’article Gestion des attributs). En revanche, si nous ne voulons pas que la nouvelle colonne soit un attribut, il faut procéder comme dans le cas de l’ajout des contrôles aux conteneurs. Afin d’étendre une liste DataGrid existante, il faut connaître son identifiant unique. Pour le connaître, il faut ouvrir la vue contenant le datagrid en mode de gestion des vues, le cliquer et trouver son LayoutId dans la rubrique Propriétés. Ensuite, nous accédons au contrôle à l’aide de la méthode RegisterDataGridExtension de la classe ModuleBase et nous implémentons l’ajout d’une nouvelle colonne dans la collection. Les paramètres de cette méthode sont :

  • dataGridLayoutId (string) – identifiant du layoutId du datagrid étendu,
  • action (Action<DataGrid, IViewModel, bool>) – délégué à la méthode qui sera appelée lors de la création du contrôle de datagrid

Exemple  1.

Nous voulons ajouter une colonne à la liste de la vue d’un nouveau reçu qui affichera l’information si la position ajoutée ne dépasse pas le montant défini.

L’identifiant Layout Id de la liste dans un reçu c’est ReceiptDocumentViewDataGrid. Dans la méthode Initialize de la classe Module nous ajoutons :

RegisterDataGridExtension("ReceiptDocumentViewDataGrid", DataGridNewColumn);

Ensuite, nous implémentons la méthode DataGridNewColumn :

private void DataGridNewColumn(DataGrid dataGrid, IViewModel viewModel, bool isDesignMode)
{
    var column = new DataGridTextColumn
    {
        Header = "Dépasse 100 ?",
        Binding = new Binding {Converter = new ValidateConverter()}
    };
 
    Layout.SetId(column, "DocumentViewDataGridExtendedColumn1"); 
    dataGrid.Columns.Add(column);
}

La valeur du paramètre isDesignMode change en true, lorsque la vue contenant ce datagrid est ouverte en mode de gestion des vues. Ensuite, nous ajoutons la classe de convertisseur ValidateConverter qui contiendra la logique retournant la valeur appropriée pour chaque cellule dans la colonne ajoutée :

internal class ValidateConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var row = value as TradeDocumentItemRow;
 
        if (row!=null)
        {
            return row.Price > 100 ? "OUI" : "NON";
        }
 
        //en cas de positions reprises
        return "Ne concerne pas";
    }
   … 
}

L’exemple ci-dessus suppose que toutes les informations requises à afficher les valeurs sont disponibles dans l’entité de ligne. Dans le cas où la logique commerciale pour la nouvelle colonne doit être également étendue, il faut d’abord télécharger les données indispensables pour la nouvelle colonne. Les données téléchargées peuvent être stockées dans une propriété publique spécialement préparée disponible dans chaque viewmodel – CustomDataDictionary. C’est une propriété du type répertoire (string, object) à laquelle nous pouvons faire appel dans la colonne définie à l’aide de binding.

 

Exemple  2.

Nous ajoutons une nouvelle colonne dans la vue du reçu qui affichera le nom du tarif du produit ajouté à la liste. L’entité de produit (IDocumentItemRow) ne contient que l’identifiant du tarif (PriceListId), mais n’a pas de son nom.

Nous commençons par télécharger la liste complète des tarifs et l’enregistrer dans le répertoire CustomDataDictionary. Il suffit de télécharger les tarifs une seule fois au début, par exemple lors de l’ouverture de vue. À ces fins, nous pouvons utiliser les extension points pour nous brancher sur la méthode après l’initialisation – AfterOnInitialization, ou par l’héritage de la classe DocumentViewModel et la surcharge de la méthode OnInitialization. Il est également possible de télécharger la liste des tarifs lors du branchement avec la nouvelle colonne, c’est-à-dire dans l’action de la méthode RegisterDataGridExtension. Aux fins de cet exemple, nous allons sélectionner cette dernière méthode.

Dans la méthode Initialize de la classe Module nous faisons appel :

RegisterDataGridExtension("ReceiptDocumentViewDataGrid", DataGridNewColumnWithCustomBL);

Ensuite, nous implémentons la méthode DataGridNewColumnWithCustomBL

private void DataGridNewColumnWithCustomBL(DataGrid dataGrid, IViewModel viewModel, bool isDesignMode)
{
       if (viewModel is CustomDocumentViewModel vm)
       {
                //fill custom dictionary with dictionary of data for custom column (priceListId => name)
                vm.CustomDataDictionary.Add(CustomColumnTest, new Dictionary<int, string>
                {
                    {1, "premier" },
                    {2, "deuxième" }
                });
 
                //after initial price changed refresh custom column binding
                vm.AfterSetInitialPrice += () => { 
                       vm.OnPropertyChanged(nameof(vm.CustomDataDictionary)); 
                };
       }
 
       var column = new DataGridTextColumn
       {
          Header = "Price list name",
          Binding = new MultiBinding
          {
            Converter = new CustomMultiConverter(),
            Bindings =
            {
              new Binding(),
              new Binding
              {
                RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DocumentView), 1),
 Path = new PropertyPath($"DocumentViewModel.CustomDataDictionary[{CustomColumnTest}]")
              }
            }
          }
       };
 
    dataGrid.Columns.Add(column);
}

Dans la première partie de la méthode, nous simulons le téléchargement des tarifs en complétant le répertoire CustomDataDictionary avec un répertoire avec deux valeurs (id du tarif, nom du tarif). Ceci est fait exprès, car CustomDataDictionary pourrait être utilisé à stocker également des autres informations (par exemple pour une autre logique commerciale). La clé CustomColumnTest est un champ du type const string défini dans la classe Module, contenant un nom unique grâce auquel il sera possible d’identifier notre collection de données (tarifs).

public const string CustomColumnTest = "CustomColumnTest";

Dans la seconde partie de la méthode, nous créons une colonne avec multibinding et un convertisseur. Le multibinding définit le binding à l’entité de ligne actuelle, ainsi qu’au répertoire avec les tarifs contenus dans le répertoire CustomDataDictionary sous la clé CustomColumnTest. Dans le convertisseur, par contre, nous obtenons les deux objets afin de pouvoir retourner le nom de la liste de prix sur la base de l’id contenu dans l’entité et du nom contenu dans le dictionnaire.

internal class CustomMultiConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var documentItemRow = values[0] as IDocumentItemRow;
            var dictionary = values[1] as Dictionary<int, string>;
 
            //if item has price list id then show price list name (when initial price changes, price list id nulls)
            if (documentItemRow?.PriceListId.HasValue ?? false)
            {
                string name = null;
                if (dictionary?.TryGetValue(documentItemRow.PriceListId.Value, out name) ?? false)
                {
                    return name;
                }
            }
 
            return null;
        }
... 
    }

L’exemple complet contient encore le branchement sur la méthode SetInitialPrice dans lequel est appelé la demande d’actualiser le binding avec CustomDataDictionary, car après la modification du prix initial, le prix affiché n’est plus le prix du tarif (la propriété PriceListId est désormais null) et la nouvelle colonne avec le nom ne doit plus l’afficher.

Le code complet des exemples est disponible dans le chapitre Ajouter une colonne à DataGrid dans une vue existante dans l’article Exemples.

Accès à un élément existant

Il est également possible d’avoir accès aux propriétées de chaque contrôle existant qui a un layoutId défini. À cette fin, il faut utiliser dans la classe Module la méthode AttachToFrameworkElement. Les paramètres de cette méthode sont analogues à ceux de la méthode RegisterDataGridExtension.

Ajouter des éléments à la zone de statut

La zone de statut se caractérise par le fait que les éléments y emplacés sont disponibles durant le fonctionnement de l’application, indépendamment des vues ouvertes. L’accès à cette zone peut se faire de tout vue de base. Afin d’ajouter à la zone de statut un contrôle avec une logique personnalisée, il faut appeler la méthode AddElementToStatusBar<TFrameworkElement> dans la méthode Initialize de la classe Module. Les arguments de la méthode sont :

  • elementLayoutId (string) – identifiant unique du contrôle ajouté,
  • styleKey (string) – nom de clé dans le fichier ModernUI.xaml où sera défini le style du contrôle
  • elementViewModelFunc (Func<IStatusBar,StatusBarEementBase>) – délégué à la méthode qui sera appelée lors de la création de contrôle

Pour voir un exemple d’implémentation, consultez le chapitre Exemple d’extension de la zone de statut dans l’article Exemples.




Créer des vues gérables

Dans l’article Créer des vues nous avons décrit les étapes de base indispensables pour créer le squelette d’une nouvelle vue. Nous avons également montré comment enregistrer une telle vue, encore vide, pour qu’elle soit gérable lors du fonctionnement de l’application (chapitre Enregistrer vues à naviguer et à gérer l’affichage dans l’article Créer de vues).

Chaque élément (contrôle) marqué avec l’identifiant unique LayoutId devient automatiquement gérable. Leur gestion c’est dans la plupart des cas une possibilité de manipuler leurs certaines propriétés comme la couleur d’arrière-plan, du texte, le formatage de la police, les marges, la largeur, la hauteur etc. Tout cela a été également décrit dans le chapitre précédent.

Les éléments gérables reçoivent une caractéristique supplémentaire au moment où ils sont déclarés à l’intérieur d’un des conteneurs disponibles dans l’application POS : Grid et ItemsContainer (de l’espace Comarch.POS.Presentation.Core.Controls). Cette caractéristique permet de déterminer si et où un élément doit être placé dans un conteneur.

Gestion des éléments dans le conteneur ItemsContainer

L’ajout de contrôles à l’intérieur du conteneur ItemsContainer entraîne leur présentation par défaut dans l’ordre où ils ont été déclarés. La particularité du conteneur fait que les éléments sont positionnés par défaut horizontalement ou verticalement, en fonction de la propriété Orientation (qui peut être également gérable) définie sur le conteneur. Si le conteneur possède le LayoutId unique, il devient gérable ce qui permet à l’utilisateur de manipuler ses éléments (tous les éléments doivent également posséder ses identifiants LayoutId uniques). Lorsque l’utilisateur active le mode de gestion de la vue contenant ce conteneur, il pourra, à l’aide de la souris, attraper n’importe quel contrôle à son intérieur et le faire glisser en modifiant l’ordre des éléments intérieurs du conteneur ou même supprimer l’élément du conteneur ou l’ajouter à nouveau.

Les éléments déclarés à l’intérieur du conteneur ItemsContainer ne peuvent exister que dans ce conteneur. Cela veut dire que l’utilisateur ne peut pas ajouter le contrôle à un autre conteneur. Cette restriction est enlevée par un conteneur du type Grid.

Exemple :

<StackPanel>
      <controls:ItemsContainer core:Layout.Id="ExampleView.ItemsContainer1">
          <TextBlock core:Layout.Id="ExampleView.TextBlock1"/>
          <Button core:Layout.Id="ExampleView.Button1"/>
      </controls:ItemsContainer>
      
      <controls:ItemsContainer core:Layout.Id="ExampleView.ItemsContainer2">
          <TextBlock core:Layout.Id="ExampleView.TextBlock2"/>
          <Button core:Layout.Id="ExampleView.Button2"/>
      </controls:ItemsContainer>
  <StackPanel>

Dans l’exemple ci-dessus nous voyons une vue composée de deux conteneurs gérables ExampleView.ItemsContainer1 et ExampleView.ItemsContainer2. Les éléments déclarés à l’intérieur de ces conteneurs seront affichés par défaut dans l’ordre dans lequel ils sont enregistrés.

Après avoir activé le mode de gestion de cette vue, l’utilisateur pourra modifier l’ordre des éléments. Il pourra supprimer un élément/des éléments du conteneur ou les y réinsérer (s’ils ont été supprimés avant). En revanche, il ne pourra pas transférer, par exemple l’élément ExampleView.TestBlock1 du conteneur ItemsContainer1 vers le conteneur ItemsContainer2. Le transfert des éléments entre les conteneurs ne sera pas possible.

Gestion des éléments dans le conteneur Grid

Un autre conteneur qui permet de manipuler ses éléments est Grid. Ce conteneur nécessite de définir une grille des colonnes et des lignes où il sera possible d’emplacer des éléments. Cette grille peut être définie par défaut dans xaml ou elle peut être gérée par l’utilisateur (l’utilisateur peut modifier le nombre de colonnes et de lignes). Par défaut, chaque élément ajouté au Grid ne sera pas affiché jusqu’à ce que l’utilisateur fasse glisser en mode de gestion l’élément dans la cellule sélectionnée du conteneur.

Il est possible de modifier l’affichage par défaut des composants pour que cela fonctionne comme dans le cas du conteneur ItemsContainer. Dans le cas où la propriété DefaultShowChildren=true, tous les éléments seront par défaut affichés dans la vue.

Comme dans le cas du conteneur du type ItemsContainer, chaque élément défini dans le conteneur Grid peut être supprimé/ajouté au conteneur. En outre, si un autre conteneur (Grid ou ItemsContainer) existe à l’intérieur du conteneur, les éléments peuvent être ajoutés directement dans le conteneur imbriqué. Grâce à cela, il est possible de transférer par exemple les contrôles entre les conteneurs ItemsContainer différents.

Exemple :

<controls:Grid core:Layout.Id="ExampleView.BaseGrid">
      <TextBlock core:Layout.Id="ExampleView.TextBlock1"/>
      <Button core:Layout.Id="ExampleView.Button1"/>
      <TextBlock core:Layout.Id="ExampleView.TextBlock2"/>
      <Button core:Layout.Id="ExampleView.Button2"/>
 
      <controls:ItemsContainer core:Layout.Id="ExampleView.ItemsContainer1">     
      <controls:ItemsContainer core:Layout.Id="ExampleView.ItemsContainer2">
  </controls:Grid>

Dans l’exemple ci-dessus, tous les contrôles ont été définis directement dans le Grid. Maintenant, lors du premier démarrage de cette vue, l’utilisateur verra une vue vide. Cela est dû au fait que, par défaut, le Grid n’affiche pas les éléments. En revanche, en mode de gestion il sera possible de définir la grille du Grid (ses colonnes et lignes) ainsi que de faire glisser dans le Grid chaque contrôle défini. Il sera également possible de transférer, par exemple, le contrôle ExampleView.TextBlock1 directement dans le conteneur ExampleView.ItemsContainer1 ou ExampleView.ItemsContainer2, après avoir ajouté au préalable ces conteneurs dans le Grid.

La grille par défaut du Grid peut être également définie dans le xaml à l’aide de la propriété ColumnDefinition et RowDefinition.  Le nombre souhaité de colonnes ou de lignes est déterminé en saisissant autant de valeurs (nombre spécifique, * ou Auto) que le nombre de colonnes/lignes souhaité, séparées par des virgules.

Ainsi, par exemple, pour définir cinq colonnes, dont la première aura une largeur de 100, la deuxième sera automatiquement sélectionnée et les autres obtiendront proportionnellement l’espace restant, la propriété ColumnDefinition doit avoir la valeur : „100,Auto,*,*,*”.

Il est également possible de définir, à l’aide de la propriété Grid.Position, l’emplacement par défaut des éléments dans une cellule appropriée du Grid. La valeur est définie à l’aide de quatre chiffres séparés par des virgules qui signifie le numéro de ligne (numérotation à partir de 0), le numéro de colonne (numérotation à partir de 0), le nombre de lignes (au moins 1) et le nombre de colonnes respectivement, qui doit être occupées par le contrôle.

Exemple :

<controls:Grid core:Layout.Id="ExampleView.BaseGrid" DefaultShowChildren="True">
        <controls:Grid.Style>
            <Style TargetType="controls:Grid" BasedOn="{StaticResource {x:Type controls:Grid}}">
                <Setter Property="ColumnDefinition" Value="*,*,*" />
                <Setter Property="RowDefinition" Value="*,*,*" />
            </Style>
        </controls:Grid.Style>
 
        <TextBlock core:Layout.Id="ExampleView.TextBlock1" Text="Hello">
            <TextBlock.Style>
                <Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
                    <Setter Property="controls:Grid.Position" Value="1,1,1,1" />
                </Style>
            </TextBlock.Style>
        </TextBlock>
 
    </controls:Grid>

Maintenant, la vue est composée du Grid pour lequel nous avons activé l’affichage des éléments par défaut et pour lequel nous avons définis trois colonnes de la même largeur (largeur définie dynamiquement, en fonction de la largeur de la vue) et trois lignes de la même hauteur (hauteur définie dynamiquement comme dans le cas de la largeur). Le conteneur contient un élément TextBlock dont la position par défaut dans le conteneur a été défini comme la cellule centrale.




Gestion de vue et de ses éléments

Les éléments d’interface (les contrôles) peuvent être modifiés en chageant les couleurs gérées directement – la couleur du motif (ThemeColor) et la couleur d’arrière-plan (ThemeBackground), dans le panneau Configuration d’interface, globalement, tous les contrôles à la fois, dans le panneau Éléments globaux ou localement, indépendamment par vue, dans le panneau Gestion des vues. La modification d’un n’importe quel paramètre de contrôle localement a une priorité plus haute qu’une modification globale.

Layout.Id

Le fonctionnement de la gestion des vues dépend de quelques facteurs. Le premier est d’enregistrer correctement la vue (utilisation de la méthode RegisterViews de la classe ModuleBase) et de créer un view-model approprié pour le mode design (DesignViewModel), le deuxième est de marquer les contrôles avec un attribut approprié.

Cet attribut est Layout.Id qui doit être unique dans l’ensemble de l’application POS. C’est une condition indispensable pour que le contrôle soit géré indépendamment. Si plusieurs contrôles ont le même Id, alors la modification d’une propriété entraînera la modification des autres contrôles.

Définir les valeurs par défaut des propriétés gérables

Les valeurs par défaut des contrôles peuvent être définies de plusieurs façons, en fonction des besoins.

1. Directement comme les attributs du contrôle défini dans xaml

<TextBlock Foreground="Red"/>

Il ne sera pas possible de gérer le contrôle ci-dessus, car l’attribut Layout.Id n’a pas été défini pour lui.

Cette méthode peut être également utilisée avec les Schémas de couleur et police :

<TextBlock Foreground="{DynamicResource ThemeColor}"/>

Le contrôle sera géré uniquement en modifiant le motif (la couleur de la police sera modifiée).

Pour qu’un contrôle soit gérable globalement dans la configuration globale d’interface, il faut l’enregistrer à l’aide de la méthode RegisterControl de la classe ModuleBase.

Pour qu’un contrôle soit gérable localement par vue où elle a été utilisée (gestion des vues), cette vue doit être enregistrée correctement (à l’aide de la méthode RegisterViews) et le contrôle doit avoir l’attribut Layout.Id. En cas d’utilisation de Layout.Id, il ne faut pas paramétrer les propriétés par défaut du contrôle directement sur lui. Si par exemple nous définissons la valeur par défaut de la propriété Foreground avant de définir Layout.Id, cette propriété sera ignorée. En revanche, si nous définissons la propriété Foreground après Layout.Id, elle ne sera pas gérable (sa valeur sera toujours remplacée par la valeur définie directement).

Une définition directe des attributs doit être effectuée uniquement pour les propriétés non-gérables comme celles qui sont indispensables au fonctionnement correct du contrôle (par exemple Binding).

2. Style global ou local de contrôle (en utilisant x:Key)

<core:View.Resources>
        <Style TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
            <Setter Property="Foreground" Value="Red"/>
            <Setter Property="Background" Value="{DynamicResource ThemeBackground}"/>
        </Style>
</core:View.Resources>
..
<TextBlock core:Layout.Id="TextBlockLayoutId" />

L’exemple ci-dessus illustre le réglage global du style de couleur de la police et de la couleur d’arrière-plan pour tous les contrôles TextBlock utilisés dans la vue <core:View> actuelle.

<core:View.Resources>
        <Style x:Key="TextBlockStyle" 
               TargetType="TextBlock" BasedOn="{StaticResource {x:Type TextBlock}}">
            <Setter Property="Foreground" Value="Red"/>
            <Setter Property="Background" Value="{DynamicResource ThemeBackground}"/>
        </Style>
</core:View.Resources>
…
<TextBlock Style="{StaticResource TextBlockStyle}" core:Layout.Id="TextBlockLayoutId" />

La modification ci-dessus présente comment définir à l’aide des styles uniquement le contrôle sélectionné.

3. Attribut par défaut défini dans ModerUI.xaml selon la définition <type_d_attribut x:Key=”[LayoutId].Default.[Nom_du_type]”>[valeur par défaut]</type_d_attribut>

Fichier ModernUI.xml

<SolidColorBrush x:Key="TextBlockLayoutId.Default.Foreground" Color="Red"/>

Fichier de vue

<TextBlock core:Layout.Id="TextBlockLayoutId" />

Pour que l’exemple ci-dessus fonctionne correctement, il est requis d’enregistrer les ressources ModernUI.xaml du module dans la classe enregistrant le module (voir le chapitre Nouveau module dans l’article Créer des vues). Dans le constructeur nous appelons :

LayoutService.RegisterResources(typeof(Module));

Les limites de cette approche lient dans l’impossibilité de définir les valeurs dynamiques et de grouper les valeurs qui se répétent sous un nom commun. Par exemple, l’utilisation suivante du code est incorrecte :

<SolidColorBrush x:Key="TextBlockLayoutId.Default.Foreground" 
            Color="{DynamicResource ThemeColor}"/>

Dans ce cas le type Color (System.Windows.Media.Color) et ThemeColor(SolidColorBrush) ne correspondent pas !

Il n’est pas recommandé d’utiliser cette méthode. Une exception est la définition des paramètres par défaut des colonnes de DataGrid.

Liste des propriétés prises en charge

Les tableaux ci-dessous contiennent un catalogue des propriétés qui sont gérées dans le panneau de configuration d’interface pour les contrôles individuels disponibles dans POS.

Propriété Nom
Propriété prise en charge [nom:type] Nom dans le panneau de gestion

Framework Element

System.Windows.FrameworkElement

 

Propriété Nom
Width : double Largeur
Height : double Hauteur
Margin : Thickness Marge
HorizontalAlignment : HorizontalAlignment Alignement horizontal
              VerticalAlignment : VerticalAlignment Alignement vertical
MaxWidth : double Largeur maximale
MaxHeight : double Hauteur maximale
Grid.Position : string Emplacement

Control

System.Windows.Controls.Control

 

Propriété Nom
Background : Brush Arrière-plan
Foreground : Brush Couleur du texte
FontSize : double Taille de la police
FontWeight : FontWeight Poids de la police
FontStyle : FontStyle Style de la police
Padding : Thickness Remplissage
Grid.Position : string Emplacement

Grid

System.Windows.Controls.Grid

 

Propriété Nom
Background : Brush Arrière-plan
Margin : Thickness Marge
Visibility: Visibility Visibilité
Width : double Largeur
Height : double Hauteur
Grid.Position : string Position

 

Comarch.POS.Presentation.Core.Controls.Grid

: System.Windows.Controls.Grid

Propriété Nom
ColumnDefinition : string Colonnes
RowDefinition : string Lignes

Border

System.Windows.Controls.Border

 

Propriété Nom
Visibility : Visibility Visibilité
Background : Brush Arrière-plan

ScrollViewer

System.Windows.Controls.ScrollViewer

: System.Windows.Controls.Control

 

Propriété Nom
VerticalScrollBarVisibility : ScrollBarVisibility Barre de défilement vertical
HorizontalSchrollBarVisibility : ScrollBarVisibility Barre de défilement horizontal
Width: double Largeur
Height : double Hauteur

 

Comarch.POS.Presentation.Core.Controls.ScrollViewer

: System.Windows.Controls.ScrollViewer

 

Propriété Nom

Separator

System.Windows.Controls.Separator

: System.Windows.FrameworkElement

 

Propriété Nom
Background : Brush Arrière-plan

TextBlock

System.Windows.Controls.TextBlock

: System.Windows.FrameworkElement

 

Propriété Nom
Background : Brush Arrière-plan
Foreground : Brush Couleur du texte
FontSize : double Taille de la police
FontWeight : FontWeight Poids de la police
FontStyle : FontStyle Style de la police
Padding : Thickness Remplissage
TextAlignment : TextAlignment Alignement du texte
Visibility : Visibility Visibilité
TextWrapping : TextWrapping Renvoi à la ligne

DoubleColorTextBlock

Comarch.POS.Presentation.Core.Controls.DoubleColorTextBlock

: System.Windows.FrameworkElement

 

Propriété Nom
FirstForeground : Brush Couleur du texte 1
SecondForeground : Brush Couleur du texte 2
Background : Brush Arrière-plan
FontSize : double Taille de la police
FontWeight : FontWeight Poids de la police
FontStyle : FontStyle Style de la police
Padding : Thickness Remplissage
Visibility : Visibility Visibilité

ErrorTextBlock

Comarch.POS.Presentation.Core.Controls.ErrorTextBlock

: System.Windows.Controls.TextBlock

 

Propriété Nom

TextBox

Comarch.WPF.Controls.TextBox

: System.Windows.FrameworkElement,

System.Windows.Controls.Control

 

Propriété Nom
BorderThickness : Thickness Encadrement
BorderBrush : Brush Couleur de l’encadrement
FocusedBorderBrush : Brush Couleur de l’encadrement (focus)
ErrorColor : Brush Couleur d’erreur
HintForeground : Brush Couleur d’indice
Hint: string Indice

 

Comarch.POS.Presentation.Core.Controls.TextBox

: Comarch.WPF.Controls.TextBox

 

Propriété Nom

Underline

Comarch.WPF.Controls.Underline

: System.Windows.FrameworkElement

 

Propriété Nom
Stroke : Brush Couleur
StrokeThickness : Thickness Épaisseur

 

Comarch.POS.Presentation.Core.Controls.Underline

: Comarch.WPF.Controls.Underline

 

Propriété Nom

ColumnDefinition

System.Windows.Controls.ColumnDefinition

 

Propriété Nom
Width : double Largeur

RowDefinition

System.Windows.Controls.RowDefinition

 

Propriété Nom
Height : double Hauteur

DataGridColumn

System.Windows.Controls.DataGridColumn

 

Propriété Nom
MaxWidth : double Largeur maximale
MinWidth : double Hauteur maximale
Width : DataGridLength Largeur
SortDirection : ListSortDirection Trier
Visibility : Visibility Visibilité
HorizontalAlignment : HorizontalAlignment Alignement horizontal

DataGridTemplateColumn

System.Windows.Controls.DataGridTemplateColumn

: System.Windows.Controls.DataGridColumn

 

Propriété Nom

DataGridTextColumn

System.Windows.Controls.DataGridTextColumn

: System.Windows.Controls.DataGridColumn

 

Propriété Nom
FontSize : double Taille de la police
Foreground : Brush Couleur du texte
FontWeight : FontWeight Poids de la police
FontStyle : FontStyle Style de la police

DataGridCell

System.Windows.Controls.DataGridCell

 

Propriété Nom
Margin : Thickness Marge
HorizontalAlignment : HorizontalAlignment Alignement horizontal

DataGridColumnHeader

System.Windows.Controls.Primitives.DataGridColumnHeader

 

Propriété Nom
Margin : Thickness Marge
HorizontalContentAlignment : HorizontalAlignment Alignement horizontal du contenu

DataGrid

Comarch.WPF.Controls.DataGrid

: System.Windows.FrameworkElement,

System.Windows.Controls.Control

 

Propriété Nom

 

Comarch.POS.Presentation.Core.Controls.DataGrid

 

Propriété Nom
RowBackground : Brush Arrière-plan de ligne
HeaderBackground : Brush Arrière-plan de l’en-tête
ScrollBarWidth : double Largeur de la barre de défilement
VerticalScrollBarVisibility : Visibility Barre de défilement vertical
HorizontalScrollBarVisibility : Visibility Barre de défilement horizontal
GroupBy : DataGridGroup Trier par
IsVirtualizingWhenGrouping : bool Virtualiser lignes
ScrollUnit : ScrollUnit Unité de glissière
Grid.Position : string Position

ItemsContainer

Comarch.POS.Presentation.Core.Controls.ItemsContainer

: System.Windows.FrameworkElement

 

Propriété Nom
Orientation : Orientation Orientation
Padding : Thickness Remplissage
Background : Brush Arrière-plan
MoreMultiButtonHeight : double Hauteur
MoreMultiButtonWidth : double Largeur
MoreMultiButtonImageHeight : double Hauteur d’icône
MoreMultiButtonImageWidth : double Largeur d’icône
MoreMultiButtonMargin : Thickness Marge
MoreMultiButtonImageMargin : Thickness Marge d’icône
MoreMultiButtonFontSize : double Taille de la police
MoreMultiButtonIsImageVisible : bool Afficher icône

Expander

Comarch.POS.Presentation.Core.Controls.Expander

: System.Windows.FrameworkElement,

System.Windows.Controls.Control

 

Propriété Nom
HeaderBackground : Brush Arrière-plan de l’en-tête
HeaderPadding : Thickness Remplissage de l’en-tête

Image

System.Windows.Controls.Image

: System.Windows.FrameworkElement

 

Propriété Nom
Stretch : Stretch Étendre
StretchDirection : StretchDirection Sens d’étirement

 

Comarch.WPF.Controls.Image

 

Propriété Nom
HorizontalAlignment : HorizontalAlignment Alignement horizontal
HorizontalContentAlignment : HorizontalAlignment Alignement horizontal du contenu
VerticalAlignment : VerticalAlignment Alignement vertical
VerticalContentAlignment : VerticalAlignment Alignement vertical du contenu

 

Comarch.POS.Presentation.Core.Controls.Image

: System.Windows.FrameworkElement

 

Propriété Nom
DefaultImageKey : ImageKey Icône par défaut

BundleImage

Comarch.POS.Presentation.Core.Controls.BundleImage

 

Propriété Nom
IconForeground : Brush Couleur
IconMargin : Thickness Marge
IconImageKey : ImageKey Icône
Width : double Largeur
Height : double Hauteur
PopupMaxWidth : double Hauteur maximale
PopupMinWidth : double Hauteur minimale

Button

Comarch.POS.Presentation.Core.Controls.Button

: System.Windows.FrameworkElement,

System.Windows.Controls.Control

 

Autres sur la base de Button, par exemple :

Comarch.POS.Presentation.Core.Controls.AcceptButton

Comarch.POS.Presentation.Core.Controls.CancelButton

Comarch.POS.Presentation.Core.Controls.SelectButton

Comarch.POS.Presentation.Core.Controls.CleanButton

Comarch.POS.Presentation.Core.Controls.TileButton

Comarch.POS.Presentation.Core.Controls.PaymentTypeTile

Comarch.POS.Presentation.Core.Controls.PrintLabelButton

Comarch.POS.Presentation.Core.Controls. ShowItemsVariantsButton

 

Propriété Nom
ImageKey : ImageKey Icône
ImageMargin : Thickness Marge d’icône
ImageWidth : double Largeur d’icône
ImageHeight : double Hauteur d’icône
ImageHorizontalAlignment : HorizontalAlignment Alignement horizontal
ImageVerticalAlignment : VerticalAlignment Alignement vertical
IsImageVisible : bool Afficher l’icône
ShortcutMargin : Thickness Marge
ShortcutWidth : double Largeur
ShortcutHeight : double Hauteur
ShortcutHorizontalAlignment : HorizontalAlignment Alignement horizontal
ShortcutVerticalAlignment : VerticalAlignment Alignement vertical
IsShortcutVisible : bool Afficher le raccourci
Shortcut : Shortcut Raccourci clavier
IsScaledShortcut : bool Mise à l’échelle du contenu
ContentMargin : Thickness Marge
ContentWidth : double Largeur
ContentHeight : double Hauteur
ContentHorizontalAlignment : HorizontalAlignment Alignement horizontal
ContentVerticalAlignment : VerticalAligment Alignement vertical
ContentVisibility : Visibility Visibilité
IsScaledContent : bool Mise à l’échelle du contenu
Orientation : Orientation Orientation
ItemsContainer.NoWrapButton : bool Ne pas agréger

RadioButton

Comarch.POS.Presentation.Core.Controls.RadioButton

: System.Windows.FrameworkElement,

System.Windows.Controls.Control

 

Propriété Nom
CheckedStateBackground : Brush Arrière-plan d’élément sélectionné
CheckedStateForeground : Brush Texte d’élément sélectionné
ImageKey : ImageKey Icône
ImageMargin : Thickness Marge d’icône
ImageWidth : double Largeur d’icône
ImageHeight : double Hauteur d’icône
ImageHorizontalAlignment : HorizontalAlignment Alignement horizontal
ImageVerticalAlignment : VerticalAlignment Alignement vertical
IsImageVisible : Visibility Afficher l’icône
ContentMargin : Thickness Marge
ContentWidth : double Largeur
ContentHeight : double Hauteur
ContentHorizontalAlignment : HorizontalAlignment Alignement horizontal
ContentVerticalAlignment : VerticalAlignment Alignement vertical
ContentVisibility : Visibility Visibilité
IsScaledContent : bool Mise à l’échelle du contenu
Orientation : Orientation Orientation

FieldControl

Comarch.POS.Presentation.Core.Controls.FieldControl

: System.Windows.FrameworkElement

 

Propriété Nom
Orientation : Orientation Orientation
LabelMargin : Thickness Marge
LabelWidth : double Largeur
LabelHeight : double Hauteur
LabelFontSize : double Taille de la police
LabelFontStyle : FontStyle Style de la police
LabelFontWeight : FontWeight Poids de la police
LabelForeground : Brush Couleur du texte
LabelForegroundError : Brush Couleur en absence de validation
LabelHorizontalAlignment: HorizontalAlignment Alignement horizontal
LabelVertivalAlignment: VerticalAlignment Alignement vertical
ContentIsRequired : bool Requis

CheckBox

Comarch.POS.Presentation.Core.Controls.CheckBox

: System.Windows.FrameworkElement,

System.Windows.Controls.Control

 

Propriété Nom
CheckedStateBackground : Brush Arrière-plan d’élément sélectionné
CheckedStateForeground : Brush Texte d’élément sélectionné
DisabledStateBackground : Brush Arrière-plan d’élément inactif
DisabledCheckedStateBackground : Brush Arrière-plan d’élément inactif sélectionné
ImageKey : ImageKey Icône
ImageMargin : Thickness Marge d’icône
ImageWidth : double Largeur d’icône
ImageHeight : double Hauteur d’icône
ImageHorizontalAlignment : HorizontalAlignment Alignement horizontal
ImageVerticalAlignment : VerticalAlignment Alignement vertical
IsImageVisible : Visibility Afficher l’icône
ContentMargin : Thickness Marge
ContentWidth : double Largeur
ContentHeight : double Hauteur
ContentHorizontalAlignment : HorizontalAlignment Alignement horizontal
ContentVerticalAlignment : VerticalAlignment Alignement vertical
ContentVisibility : Visibility Visibilité
IsScaledContent : bool Mise à l’échelle du contenu
Orientation : Orientation Orientation

ComboBox

Comarch.WPF.Controls.ComboBox

: System.Windows.FrameworkElement,

System.Windows.Controls.Control

 

Propriété Nom
HorizontalContentAlignment : HorizontalAlignment Alignement horizontal du contenu
PopupBackground : Brush Arrière-plan
FocusedBorderBrush : Brush Couleur de l’encadrement (focus)
ErrorColor : Brush Couleur d’erreur

 

Comarch.POS.Presentation.Core.Controls.ComboBox

: Comarch.WPF.Controls.TextBox

 

Propriété Nom

ComboBox2

Comarch.POS.Presentation.Core.Controls.   ComboBox2

 

Propriété Nom
LabelFontSize : double Taille de la police
LabelFontStyle : FontStyle Style de la police
LabelFontWeight : FontWeight Poids de la police
Shortcut : Shortcut Raccourci clavier
FontSize : double Taille de la police
FontWeight : FontWeight Poids de la police
FontStyle : FontStyle Style de la police
Visibility : Visibility Visibilité

AutoCompleteComboBox

Comarch.POS.Presentation.Core.Controls.AutoCompleteComboBox

: System.Windows.Controls.Control

 

Propriété Nom
HintForeground : Brush Couleur d’indice
Hint: string Indice
FocusedBorderBrush : Brush Couleur de l’encadrement (focus)
ErrorColor : Brush Couleur d’erreur

SwitchBox

Comarch.POS.Presentation.Core.Controls.SwitchBox

: System.Windows.Controls.Control

 

Propriété Nom
VerticalContentAlignment : VerticalAlignment Alignement vertical du contenu
Margin : Thickness Marge

SearchBox

Comarch.POS.Presentation.Core.Controls.SearchBox

 

Propriété Nom
FontSize : double Taille de la police
Foreground : Brush Arrière-plan
HintForeground : Brush Couleur d’indice
Margin : Thickness Marge
Hint: string Indice

DatePicker

Comarch.POS.Presentation.Core.Controls.DatePicker

: System.Windows.Controls.Control

 

Propriété Nom
FocusedBorderBrush : Brush Couleur de l’encadrement (focus)
ErrorColor : Brush Couleur d’erreur
BorderBrush : Brush Couleur de l’encadrement
Visibility : Visibility Visibilité

ButtonSpinner

Comarch.POS.Presentation.Core.Controls.ButtonSpinner

 

Propriété Nom
ButtonImageWidth : double Largeur
ButtonImageHeight : double Hauteur
ButtonWidth : double Largeur du bouton
ButtonHeight : double Hauteur du bouton

FilterItemsControl

Comarch.POS.Presentation.Core.Controls.FilterItemsControl

Propriété

Nom

MaxFilterItemsPerRow : int Nombre de filtres maximal

Visibility : Visibility

Visibilité

Grid.Position : string

Position

SearchBoxFilter

Comarch.POS.Presentation.Core.Controls.SearchBoxFilter

: Comarch.POS.Presentation.Core.Controls.ComboBox2

 

Propriété Nom
DefaultFilter : string Valeur de filtre par défaut

StockTile

Comarch.POS.Presentation.Core.Controls.StockTile

 

Propriété Nom
Background : Brush Arrière-plan
IsCodeVisible : bool Afficher le code d’entrepôt
WarehouseMargin : Thickness Marge
WarehouseCodeFontSize : double Taille de la police du code
WarehouseNameFontSize : double Taille de la police de la désignation
StocksFontSize : double Taille de la police
StocksMargin : Thickness Marge

SetValueNumbersKeyboard

Comarch.WPF.Controls.SetValueNumbersKeyboard

 

Propriété Nom
Visibility : Visibility Visibilité

AttributeControl

Comarch.POS.Presentation.Core.Controls.AttributeControl

: System.Windows.Controls.Control

 

Propriété Nom

AssistantControl

Comarch.POS.Presentation.Core.Controls.AssistantControl

 

Propriété Nom
LabelFontSize : double Taille de la police
LabelFontStyle : FontStyle Style de la police
LabelFontWeight : FontWeight Poids de la police
FontSize : double Taille de la police
FontWeight : FontWeight Poids de la police
FontStyle : FontStyle Style de la police
Shortcut : Shortcut Raccourci clavier
Visibility : Visibility Visibilité
Grid.Position : string Position

DocumentKeypad

Comarch.POS.Presentation.Core.Controls.DocumentKeypad

 

Propriété Nom
HeaderFontSize : double  
KeypadHeaderColor : Brush