Die Idee des Dialogsystems unterscheidet den Dialogentwickler von dem Entwickler, der den Dialog nutzt. Der Entwickler implementiert einen Dialog, der über Parameter gesteuert eine Aufgabe erfüllt. Über ein Objekt wird das Ergebnis des Dialoges zur Verfügung gestellt.
Der Nutzer des Dialoges ruft den Dialog auf und setzt die Parameter entsprechend seinen Anforderungen. In einer Callbackfunktion wird ihm das Ergebnis des Dialoges zurückgeliefert. Damit wird sichergestellt, dass der Dialog beliebig technisch umgestellt werden kann, da der Nutzer keinen Zugriff auf den Dialog hat.

Dialogklasse

Ein Dialog besteht aus einer Dialogklasse mit zwei Methoden.

[DialogImplementation("BA.Customer.Project.MyDialog")]
public class MyDialog : DialogImplementationBase
{
    public override void CreateDialogContent(
        DevExFormModel formModel, // Das Formmodel zur Darstellung des Dialoges
        HttpRequestBase request, // Der HttpRequest
        ModelStateDictionary modelState, // Der Status des verwendeten Models
        Dictionary<String, Object> parameter, // Die Parameter des Dialoges
        object bindObject = null // Das Model mit den Daten
    )
    { .... }
    public override DialogResultModel HandleAction(
        HttpRequestBase request, // Der HttpRequest
        ModelStateDictionary modelState, // Der Status des verwendeten Models
        Dictionary<String, Object> parameter, // Die Paramter des Dialoges
        String buttonId, // Die ID des gedrückten Buttons
        object bindObject, // Das Model mit den Daten
        string propertyPrefix = "" // Der mögliche Prefix von Werten
    )
    {
        DialogResultModel result = base.HandleAction(request, modelState, parameter, buttonId, 
                                                     bindObject, propertyPrefix);
        return result;
    }
}

Die Klasse muss zwei Voraussetzungen erfüllen

  1. Sie muss die Klasse DialogImplementationBase erweitern.
  2. Über das Attribute DialogImplementation wird der Dialogidentifier festgelegt

Die Methode HandleAction muss nicht überschrieben werden.

CreateDialogContent

In dieser Methode wird der Inhalt des Dialoges implementiert. Diese Methode wird bei allen Aktualisierungen aufgerufen und kann jeweils einen anderen Inhalt generieren.

Einfacher Dialog mit einer Textbox

public override void CreateDialogContent(DevExFormModel formModel, HttpRequestBase request, ModelStateDictionary modelState, Dictionary<String, Object> parameter, object bindObject = null)
{
        formModel.Title = "Dialogtitel";
        formModel.DataSource = null;

        TextEditControl textControl = new TextEditControl()
        {
            Id = "4095021E-6762-4894-8B42-9164EBC1281F".ToGuid(),
            Caption = "Text"
        };
        Controls.Add(textControl);

        formModel.AddButton(DialogButtonIds.OkButton, "OK", true);
        formModel.AddButton(DialogButtonIds.CancelButton, "Cancel", false, "BA.Ui.Dialog.DialogManager.DialogDefaultCancel");
}

Mit Hilfe eines Datenmodels werden die Maskensteuerelemente gebunden

public override void CreateDialogContent(DevExFormModel formModel, HttpRequestBase request, ModelStateDictionary modelState, Dictionary<String, Object> parameter, object bindObject = null)
{
    formModel.Title = "Dialogtitel";

    MyDialogModel datenModel;
    if (bindObject == null)
    {
        datenModel = new MyDialogModel();
        datenModel.TextEdit = "Vorgabewert";
    }
    else
        datenModel = (MyDialogModel)bindObject;

    formModel.DataSource = datenModel;

    TextEditControl textControl = new TextEditControl()
    {
        Id = "4095021E-6762-4894-8B42-9164EBC1281F".ToGuid(),
        Caption = "Text",
        OrmFieldName = "TextEdit"
    };
    Controls.Add(textControl);

    formModel.AddButton(DialogButtonIds.OkButton, "OK", true);
    formModel.AddButton(DialogButtonIds.CancelButton, "Cancel", false,
            "BA.Ui.Dialog.DialogManager.DialogDefaultCancel");
}

public class MyDialogModel
{
    public String TextEdit { get; set; }
}

Buttons

Mit AddButton() werden Buttons zu Dialogen hinzugefügt. Entweder gibt man die 4 wichtigsten Parameter direkt an:

formModel.AddButton(DialogButtonIds.CancelButton, "37857EB7-EDBC-4419-9823-6FC107794621".Translate(), false, "BA.Ui.Dialog.DialogManager.DialogDefaultCancel");

Oder man erstellt ein DialogButtonDefinition Model mit allen Eigenschaften und übergibt dieses als Parameter:

DialogButtonDefinition okButton = new DialogButtonDefinition() {
     ButtonId = DialogButtonIds.OkButton,
     Caption = Api.Text.Format("68B063D1-9626-4015-BCC8-8D41C76B8596"),
     ServerCallback = true,
     IsEnabled = true,
     HintText = "Jetzt Speichern"
};
formModel.AddButton(okButton);

Im Folgenden eine Übersicht möglicher Parameter.

  • ButtonId Die ID des Buttons.
  • Caption Die Beschriftung des Buttons.
  • ServerCallback Gibt es ein Server-Callback
  • FunctionName Der Name (mit Pfad) der Client-Action.
    Nur wenn es kein Server-Callback ist.
  • IsEnabledOptional: Soll der Button aktiv sein (Vorgabe: true)
  • HintText Optional: Hinweistext / Tooltip wenn die Maus über dem Button ist.

HandleAction

In HandleAction werden die Buttons verarbeitet, die auf serverCallback=true stehen. Per Default wird der Dialog geschlossen. Ein anderes Verhalten wird an dieser Stelle implementiert. In dem Beispiel wird das Feld TextEdit validiert und eine entsprechende Fehlermeldung ausgegeben.

public override DialogResultModel HandleAction(HttpRequestBase request, ModelStateDictionary modelState, Dictionary<String, Object> parameter, String buttonId, object bindObject, string propertyPrefix = "")
{
    DialogResultModel result = base.HandleAction(request, modelState, parameter, buttonId, bindObject, propertyPrefix);
    if (buttonId == DialogButtonIds.OkButton)
    {
        MyDialogModel dlgData = (MyDialogModel)bindObject;
        if (String.IsNullOrWhiteSpace(dlgData.TextEdit))
        {
            result.Message = "Es ist ein Fehler aufgetreten!";
            result.MessageType = EnumToastNotificationType.Error;
            result.InvalidFields.Add("TextEdit");
            result.FieldMessages.Add("Das Textfeld ist leer.");
            result.Action = "";
        }
    }
    return result;
}

Ergebnis für den Anwender, wenn die Validierung fehlschlägt.

Dialog Validation

Browser Funktionalitäten

Werden im Browser Funktionalitäten implementiert, muss beachtet werden, dass die Maskensteuerelemente in den Dialogen mit einem Präfix versehen sind. Um den korrekten Namen eines Steuerelementes zu erhalten, steht eine entsprechende Methode im DialogManager zur Verfügung. Beispiel:

public static MyDialogButton(button: BADialogButton, evt: ASPxClientButtonClickEventArgs) {
    let textBoxName: string = BA.Ui.Dialog.DialogManager.GetDialogControlName(button, "TextEdit");
    if (window[textBoxName]) {
        let box: BAClientTextBox = <BAClientTextBox>window[textBoxName];
        box.SetValue("Neuer Wert");
    }
}

Höhe und Breite / Adaptives Layout

Das Prinzip in der Darstellung der Dialoge basiert auf einer vorgegebenen Breite und einer automatisch berechneten Höhe. Die Standardbreite eines Dialoges ist 600 Pixel. Bei der Implementierung sollte man für seinen Dialog die entsprechende Breite angeben.

formModel.Width = 600;

Die Höhe wird anschließend von dem System automatisch berechnet. Alternativ kann man die Höhe ebenfalls definieren.

Das Framework der Maskensteuerelemente unterstützt das Adaptive Layout von DevExpress. Siehe dazu auch die DevExpress Online Dokumentation. Folgende Screenshots desselben Dialoges mit unterschiedlichen Breiten verdeutlichen die Möglichkeiten.

Breiter Dialog (Zweispaltig / Labels vor dem Feld)

Dialog Layout 1

Mittlerer Dialog (Zweispaltig / Labels über dem Feld)

Dialog Layout 2

Schmaler Dialog (Einspaltig / Labels über dem Feld)

Dialog Layout 3

Basis ist ein LayoutPanelControl. Beispiel

LayoutPanelControl layout = new LayoutPanelControl()
{
    Id = "DEB77CD6-1823-445F-A70D-A0E6001E4351".ToGuid(),
    ColumnCount = 2,
    WrapContentAtWidth = 500,
    StretchLastItem = true,
};
layout.AddBreakpoint(new BreakpointRule() { Name = "S", ColumnCount = 1, MaxWidth = 700 });
layout.AddBreakpoint(new BreakpointRule() { Name = "M", ColumnCount = 2, MaxWidth = 1000 });

Bei den Steuerelementen wird dann jeweils deren Verhalten definiert.

TextEditControl textControl = new TextEditControl()
{
    Id = "4095021E-6762-4894-8B42-9164EBC1281F".ToGuid(),
    Caption = "Text",
    OrmFieldName = "TextEdit",
    ColSpan = 2,
};
textControl.AddSpanRule((new SpanRule() { BreakpointName = "S", ColumnSpan = 1 });
textControl.AddSpanRule((new SpanRule() { BreakpointName = "M", ColumnSpan = 2 });

Bei Gruppenelementen legt man sowohl die Breakpoints für die Gruppe als auch die eigenen Spanrules fest.

var group = new GroupControl
{
    Id = "E398BFE6-202D-4F14-9B09-FE059B314E2A".ToGuid(),
    Caption = "",
    WrapContentAtWidth = 500,
    StretchLastItem = true,
    ColumnCount = 2
};
group.AddBreakpoint(new BreakpointRule() { Name = "S", ColumnCount = 1, MaxWidth = 300 });
group.AddBreakpoint(new BreakpointRule() { Name = "M", ColumnCount = 2, MaxWidth = 500 });
group.AddSpanRule(new SpanRule() { BreakpointName = "S", ColumnSpan = 1 });
group.AddSpanRule(new SpanRule() { BreakpointName = "M", ColumnSpan = 2 });

Maskensteuerelemente für Dialoge

In eigenen Dialogen können alle Maskensteuerelemente genutzt werden, die das Attribut [EnabledForFreeDialogs] haben. Es können in der Regel die Steuerelemente nicht genutzt werden, die zwingend einen Datensatz erfordern. Beispielsweise sind das Relationsauswahlelemente.

Werden eigene Maskensteuerelemente implementiert und sollen diese in eigenen Dialogen genutzt werden, müssen sie mit dem Attribut [EnabledForFreeDialogs] versehen werden.

Aufruf

Der Aufruf eines Dialoges erfolgt über den DialogManager

BA.Ui.Dialog.DialogManager.OpenDialog(
     "BA.Customer.Project.MyDialog ", // Dialog Identifier
     { "para1": "Wert" }, // Parameterobjekt
     customData, // CustomData Objekt. Wird 1 zu 1 an die resultFunc übergeben
     resultFunc // Function die beim Beenden des Dialoges aufgerufen wird
);

Signatur der Ergebnisfunktion

function (result: BA.Ui.Dialog.DialogResult, customData: CustomData) { }

Standarddialoge modifizieren

Unter Umständen ist es notwendig das Verhalten eines Standarddialoges zu modifizieren. Dies birgt immense Risiken und sollte nur sehr bedacht getan werden. Auch sollte nach jedem Update diese Anpassung kontrolliert werden, da Änderungen an den Standarddialogen nicht kommuniziert werden.

Zwei Methoden können überschrieben werden, um in abgeleiteten Dialogen Änderungen an den erstellten Controls und an den erstellten MVCxFormLayoutItems zu machen:

void AfterContentCreated(DevExFormModel formModel, HttpRequestBase request, ModelStateDictionary modelState, Dictionary<string, object> parameter, object bindObject)

Abfolge ist:

  1. CreateDialogContent
  2. Übernahme von formModel.DataSource als bindObject
  3. AfterContentCreated

Das bedeutet, dass man in AfterContentCreated Änderungen an this.Controls durchführen kann, bevor die Controls in MVCx-Items umgewandelt werden.

Theoretisch erfüllt ein Überschreiben von CreateDialogContent mit Aufruf von base.CreateDialogContent den gleichen Zweck, man spart sich bei der Verwendung von AfterContentCreated allerdings, dass man an den base-Aufruf denken muss, d.h. AfterContentCreated ist die offizielle Schnittstelle, um Änderungen an den vom Dialog erstellten Controls zu machen.

void AfterControlsRendered(DevExFormModel formModel, HttpRequestBase request)

Hier können Änderungen an den umgewandelten MVCx-Items gemacht werden.

Diese finden sich unter formModel.LayoutPanels (Liste von DevExFormPartModel) und sind nach ihrer Hierarchie angeordnet (d.h. wenn man nicht weiß, nach was man wo sucht, muss man wahrscheinlich zunächst FlattenControls bemühen müssen).