Es wird eine neue C# Klasse benötigt. Typischerweise wird diese im Ordner „Configuration\Navigation\ClientAction“ abgelegt. Die Basisklasse ist ClientActionBase, und es müssen drei Attribute gesetzt werden. Wie alle anderen Konfigurationen muss auch diese serialisier bar sein, mit Toolbox wird die Aktion in der Toolbox für die Navigationen registriert und mit ControlFilter wird die Aktion nur für die Ribbon bar sichtbar gemacht.

[Serializable]
[Toolbox(EnumConfigurationType.NavigationConfigurationGuid, true)]
[ControlFilter(nameof(NavigationConfiguration.NavigationConfigurationType), ExpressionType.Equal, EnumNavigationConfigurationType.RibbonNavigationGuid, EnumControlFilterApplyState.OptIn)]
public class ClientActionMyAction : ClientActionBase { }

Im Konstruktor werden die wichtigsten Eigenschaften einer Aktion festgelegt (Siehe Beispiel). Folgende Punkte müssen beachtet werden.

  • Anstatt Klartext sollte bei den Eigenschaften „ToolboxName“, „Caption“, „ToolboxGroupName“ und „DesignerHintText“ immer eine Translation Guid benutzt werden.
  • Der „ControlInitName“ sollte Eindeutig sein. Also immer mit eigenen Präfixen arbeiten.
  • Für „Id“ muss immer eine eigene Guid erzeugt werden.
public ClientActionMyAction() : base()
{
    ToolboxName = "Meine Aktion";
    Caption = "Meine Aktion";
    ControlInitName = "TrainingMyAction";
    ToolboxGroupName = "Training Aktionen"; // Translation Guid verwendbar
    Id = new Guid("[INSERT ACTION GUID]");
    Icon = "projector";
    IconName = Icon;
    DesignerHintText = "Meine Aktion tut genau das, was gewünscht wird."; // Translation Guid verwendbar
    VisibilityForParentTypes.Add(EnumActionVisibleForParentType.Form);
}

Mit dem Objekt VisibilityForParentTypes kann man steuern für welche Objekte (Masken / Ansichten / Detailansichten) die eigene Aktion prinzipiell verwendet werden kann.
Damit ist schon eine eigene Aktion so implementiert, dass sie im Designer konfiguriert werden kann.

Die registrierte Aktion kann nun in dem Konstruktor der C# Klasse hinterlegt werden.

ActionMethodId = "BA.Training.ClientActionMyAction"; 

Damit ist das Grundgerüst einer konfigurierbaren Aktion erstellt.

Drag & Drop Regel

Bei jedem Steuerelement, welches im Designer zur Konfiguration genutzt werden soll, muss man darauf achten, dass die Drag & Drop Regeln korrekt gesetzt sind. Näheres dazu findet man in dem speziellen Kapitel.

Meistens werden für Aktionen auf Basis von ClientActionBase keine weiteren Regeln benötigt.

Wichtige Klassen zur Definition von Regeln

  • NavigationConfiguration Hauptknoten
  • NavigationGroupControl Navigationsgruppe
  • ExtendedNavigationGroupControl Erweiterte Navigationsgruppe
  • ClientActionBase Basis aller Aktionen
  • DropDownAction Aufklappelement

Eigenschaften

Den Aktionen kann man Eigenschaften geben, die in der Konfiguration angepasst werden. Beispiel:

[PropertiesGroup("Kundengruppe")] // Übersetzungs GUID verwendbar
[DisplayName("Toastermeldung")] // Übersetzungs GUID verwendbar
[Translate("Training")]
[HelpText("Das ist die Nachricht, die im Toaster ausgegeben wird.")] // Übersetzungs GUID verwendbar
public string Message { get; set; }

Übertragung von Werten an die Type Script Funktion

In der Methode AdditionalRibbonButtonAssignment können Daten in das AdditionalClientData Objekt geschrieben werden, welche anschließend in der Type Script Funktion verwendet werden können. Das Beispiel übersetzt den Inhalt einer Eigenschaft in die Sprache des Anwenders und überträgt den Wert.

public override void AdditionalRibbonButtonAssignment(RibbonButtonItem ribbonItem, Dictionary<string, object> additionalClientData, EnumActionVisibleForParentType parentType, DevExUIModelBase uiModel, OrmBABase orm)
{
    base.AdditionalRibbonButtonAssignment(ribbonItem, additionalClientData, parentType, uiModel, orm);
    additionalClientData["Message"] = Api.Text.Format(Message);
}

Der Wert kann nun in der Type Script Funktion verwendet werden.

public static ClientActionMyAction(event: any, customData: CustomData) {
    alert(customData.Message as string);
}

Aktiv / Inaktiv der Aktion

Wenn Aktionen in Masken verwendet werden, kann es Situationen geben, in denen die Aktionen nicht ausgeführt werden dürfen. Dazu verwendet man das Objekt DynamicClientVisibility und fügt diesem bestimmte Verhalten hinzu.

Rechte bei einer Maskenaktion

Aktionen sind häufig nur dann möglich, wenn der Benutzer bestimmte Rechte besitzt. Beispielsweise Bearbeitungsrechte auf einem Datensatz. Falls dies bei der eigenen Aktion der Fall ist, muss im Konstruktor folgende Zeile hinzugefügt werden:

DynamicClientVisibility.Add(EnumActionVisibility.IfUserHasRole);

Benötigte Client Daten

additionalClientData["UserHasRole"] = [true/false];

Beispiel für die Bearbeitungsrechte

additionalClientData["UserHasRole"] = orm?.UserCanEdit() ?? true;

Rechte in einer Ansichtenaktion

Im Gegensatz zu einer Aktion in einer Maske, kann in einer Ansicht nicht die Rechte auf einen konkreten Datensatz geprüft werden. In diesem Fall werden die Rechte des Anwenders auf der Datenbanktabelle geprüft und abhängig von den selektierten Datensätzen und deren Typ, die Aktion aktiv/inaktiv geschaltet. Werden alle Datensätze der Ansicht selektiert, wird automatisch angenommen, das auch alle Typen die in der Ansicht dargestellt werden können, markiert sind. In diesem Fall wird keine Prüfung aller Datensätze vorgenommen.

Falls dies bei der eigenen Aktion der Fall ist, muss im Konstruktor folgende Zeile hinzugefügt werden:
DynamicClientVisibility.Add(EnumActionVisibility.IfUserHasRole);

Benötigte Client Daten

additionalClientData["TypesUserCanHandle"] = [Komma separiete Liste der Typ-Guid mit Großbuchstaben];

Beispiel für Bearbeitungsrechte

// Die Typen aller in der Ansicht konfigurierten Datentabellen ermitteln
// Basistypen werden dabei aufgelöst
IEnumerable<OrmDataSourceCacheModel> ormDataSources = Api.ORM.GetOrmTypeCacheValuesByBase(GuidSet.ParseGUIDs(gridConfiguration.OrmDataSource)); 

// Keine Basistypen (Von denen können keine Datensätze existieren) und alle Datentabelle auf die der Anwender Bearbeitungsrechte prinzipiell besitzen könnte
ormDataSources = ormDataSources.Where(ff => !ff.IsBaseType && Api.User.CurrentUserIsAllowed(ff.Guid, EnumTableOperations.Delete));

// Umwandeln in eine Komma separiete Guid-Liste mit Großbuchstaben
additionalClientData["TypesUserCanHandle"] = GuidSet.JoinGUIDs(ormDataSources.Select(ff => ff.Guid)).ToUpper();

Weitere Möglichkeiten

Die Auswahlliste EnumActionVisibility beinhaltet eine Reihe weiterer Möglichkeiten. Die prinzipielle Verwendung ist immer identisch. Im Konstruktor wird das Verhalten definiert und die dazu benötigten Daten werden in das AdditionalClientData Objekt geschrieben. Ein paar Beispiele:

Datensatz muss gespeichert sein

DynamicClientVisibility.Add(EnumActionVisibility.OnlyWhenSaved);

Maskenwert beinhaltet einen definierten Wert

DynamicClientVisibility.Add(EnumActionVisibility.IfFormValueContainsValue);
additionalClientData["TestValueContains"] = "Hallo";
additionalClientData["TestFormContains"] = "Subject";

Maskenwert beinhaltet einen definierten Wert nicht

DynamicClientVisibility.Add(EnumActionVisibility.IfFormValueNotContainsValue);
additionalClientData["TestValueNotContains"] = "Hallo";
additionalClientData["TestFormNotContains"] = "Subject";

Clientside Funktion liefert True zurück

DynamicClientVisibility.Add(EnumActionVisibility.IfMethodReturnsTrue);
additionalClientData["IfMethodReturnsTrueMethod"] = "BA.Customer.Project.Ui.Utils.CheckVisibility"; 

Type Script:

public static CheckVisibility(menuItem: BAClientRibbonItem | BAClientDetailGridMenuItem, customData: CustomData) { ... }

Sichtbar in Masken und/oder Ansichten

DynamicClientVisibility.Add(EnumActionVisibility.OnlyForFormMode);
DynamicClientVisibility.Add(EnumActionVisibility.OnlyForGridLocation);

Selektierte Datensätze sind von bestimmten Datetabellen

DynamicClientVisibility.Add(EnumActionVisibility.IfUserHasRightsOverAnySelectedRowType);
additionalClientData["TypesUserCanHandle"] = allowedTypes.ToString().ToUpper();