Dynamische Controls in ASP.NET MVC erstellen


Als ich mich mit der Thematik erstellen von Dynamischen Controls in ASP.NET auseinander setzten musste, war es gar nicht so einfach Informationen zu finden wie das ganze im Detail in MVC abläuft und funktioniert dabei hat mir prinzipiell erst einmal der folgende stackoverflow Beitrag geholfen.

Es ist eigentlich egal wo die Daten herbekommt welche Controls von euch dynamisch erstellt werden sollen, die Daten können aus einer XML-Datei oder auch der Datenbank kommen. Dabei gibt es quasi 3 Schritte zu beachten.

1. Das Erstellen der passenden Eingabecontrols auf der Oberfläche:

Ich habe mir dazu eine eigene HTML-Helper Extension geschrieben, welcher ich eine Liste mit den Controls und den Daten übergebe die angezeigt / bearbeitet werden sollen, diese Daten befinden sich bereits im Model was angezeigt werden soll und muss nur noch an die Helper Methode übergeben werden, diese übernimmt dann den Rest. Es ist auch möglich das ganze über “EditorTemplates” im “Shared” Folder zu machen, was ich als schwieriger und unübersichtlicher empfand wie das ganze in eine Extension auszulagern die einen MvcHtmlString zurück gibt.

Dann wird je nach Datentyp, der erstellt werden soll, das passende Control erstellt, z.B. eine Textbox, Dropdownliste oder Checkbox. Beim Erstellen der Controls kann z.B. auf die Client Validation von MVC zurück gegriffen werden, hier müsst ihr nur die passenden “data-“ Attribute im Control setzten, was ihr erstellt.

Außerdem solltet Ihr darauf achten das Ihr den Controls entsprechende Namen (Ids) gebt die Ihr bei einem Postback auch wieder dementsprechend auswerten könnt.

Das war der einfache Teil :-), jetzt folgt das Auslesen der Daten.

2. Auslesen der eingegebenen Daten bei einem Postback:

Wenn ihr einmal soweit seid das Ihr die passenden Controls auf der Oberfläche darstellen könnt, dann wollt Ihr die Daten bei einem Postback ja auch wieder auslesen und wissen was der Benutzer eingegeben hat. Hier müssen zwei Schritte durchgeführt werden, damit dies reibungslos funktioniert.

2.1 Schreiben eines eigenen Modelbinders:

Ich habe es aber nur geschafft in dem ich die Methode “BindProperty” überschrieben habe. (Es gibt auch noch Möglichkeiten mit dem “IModelBinder” Interface zu arbeiten, hier habe ich es aber nicht geschafft, das meine Funktionen aus dem Interface aufgerufen wurden, wenn jemand einen Tipp hat bin ich dafür sehr dankbar.)

image

In unserer überschriebenen Methode prüfen wir ob das aktuelle Property was ausgewertet werden soll, dem entspricht welches wir selbst auswerten wollen, denn die Funktion wird “BindProperty” wird für jedes Property aus unserem Model aufgerufen. Da für unseren Typ bzw. in meinem Fall übergebe ich dem Model eine Liste mit Dynamischen Datentypen, kein Verfahren existiert wie diese Daten aus dem Postback dem Model hinzugefügt werden können, müssen wir die Daten entsprechend selbst auslesen aus dem Postback. Das wird wie schon gesagt in der “BindProperty” Methode gemacht. Hier warte ich bis das Property vom Typ “IENumerable<EFDynamicData>” mit Daten gefüllt werden soll.

image

Wenn unser Property mit Daten gefüllt werden soll auf das wir dann im Controller zugreifen können, müssen wir dementsprechend alle Postdaten unserer Customcontrols auslesen. Dafür suche ich meist erst einmal alle Postback values aus dem aktuellen HttpContext heraus und werte diese dann aus.

image

Dann muss auch eine Variable von unserem Typen angelegt werden “List<EFDynamicData>” damit wir diese mit den Daten aus dem Postback füllen können und erst wenn unsere Variable “dynamicDataList” mit “Setproperty” auch unserem “Model” zugewiesen wurde:

image

können wir im Controller einfach auf unsere Modelvariable zugreifen, die unsere Daten aus dem Postback enthält und können die Daten dann dementsprechend unserem Datenmodell zuweisen.

Ob Daten im gültigen Wertebereich eingegeben wurden, prüfe ich bereits im “BindProperty”, denn hier hat man die Möglichkeit direkt Fehler dem Modelstate hinzuzufügen, was es später im Controller ermöglicht einfach nur zu prüfen “ModelState.IsValid”. Sobald ein Error dem ModelState hinzugefügt wurde ist dieser nicht mehr Valide.

image

Wenn das aktuelle Property nicht unserem Typ entspricht den wir im “BindProperty” suchen, dann muss dieses Property mit den Standardmitteln dem Model hinzugefügt werden, damit wir auch auf alle anderen Properties im Controller zugreifen können:

image

2.2 Datentyp zur Modelbinder Liste hinzufügen

Damit unser Selbst geschriebener Modelbinder aber auch aufgerufen wird, muss jedes Model in dem unser Typ vorkommt der Liste mit ModelBindern in der Global.asax im Application_Start hinzugefügt werden.

image

d.h. für obiges Beispiel, das immer wenn das “EditUserAdminModel” verwendet wird unser Modelbinder zum Einsatz kommt und wenn in diesem Model dann noch der Typ “IENumerable<EFDynamicData>” gefunden wird, dann werden unsere Funktionen genommen um die Liste mit Daten zu füllen. Wenn unser Typ noch in anderen Models benutzt wird, dann muss jedes dieser Models auch in der Global.asax der Liste mit den “ModelBinders” hinzugefügt werden.

(Wie bereits erwähnt muss das ganze auch funktionieren in dem man nur den Typ registriert “IENumerable<EFDynamicData>” und damit nicht jedes einzelne Model der Liste hinzufügen muss, nur leider war es mit nicht möglich diese Variante zum Laufen zu bekommen. Wenn jemand Tipps hat, würde ich mich sehr über einen Kommentar freuen)

Ich kann NICHT garantieren, das es sich hierbei um die einzige und “beste” Methode handelt, so etwas umzusetzen aber es funktioniert einwandfrei.

Advertisements

5 Gedanken zu „Dynamische Controls in ASP.NET MVC erstellen

  1. Abt

    Hallo Squadwuschel, Du solltest MVC in keinster Weise mit WebForms vergleichen. Es gibt auch in MVC keinen Postback!
    Den DefaultModelBinder sollte man auch nicht ohne weiteres einfach überschreiben, da er noch ein wenig mehr tut, als Du hier erläuterst. Zudem hat der MVC ModelBinder aktuell einen Bug, siehe auch http://www.mycsharp.de/wbb2/thread.php?postid=3674592#post3674592

    Du hast hier in meinen Augen einen zu starken Gedanken an die undurchsichtige Arbeitsweise von WebForms und die eigentlichen Dinge von MVC missachtest Du.

    Gefällt mir

    Antwort
  2. SquadWuschel Autor

    Hallo Abt,

    wenn man einen Button Klickt zum abensenden des Formulars löse ich doch einen Postback meiner Daten aus oder sehe ich das falsch?

    Mich würde gern interessieren welche eigentlichen Dinge von MVC zu meinst die ich missachte, bzw. hast du evtl. einen alternativen Vorschlag wie man so etwas sonst umsetzen könnte oder einen guten Link wo so was im ansatz beschrieben ist, Habe mich da etwas schwer getan und nicht wirklich viel gefunden zur Materie.

    Gefällt mir

    Antwort
  3. Abt

    Es gibt keinen Postback bei MVC. Das gibt es nur bei WebForms.
    WebForms ist ein Event-basierendes System. MVC hingegen ein Request-basierendes.

    Bei MVC löst jede Aktionen einen neuen Request auf dem Server aus. Deswegen gibt es auch keine Page_LifeCycle, sondern nur (Areas,) Controllers und Actions, die man aufgrund des Anfragetyps (GET; POST) auch noch unterscheidet. Aber einen Postback gibt es nicht. Du vermischt hier einiges.

    Gefällt mir

    Antwort
  4. Lars

    @Abt: Du sagst zwar, dass hier was falsch ist, aber bietest wie vom Autor angefragt keine Alternative an. Erklär doch mal, wie macht mans richtig? Selbst 1,5 Jahre später findet man immernoch kaum was im Netz zu dem Thema.

    Gefällt mir

    Antwort
    1. SquadWuschel Autor

      Ich bin mir der Oben aufgezeigten Lösung sehr zufrieden funktioniert soweit ganz gut, daher habe ich auch nicht weiter gesucht. Den kompletten Quelltext findet man auch bei mir unter Codeplex – https://squadwuschel.codeplex.com/
      z.B. unter: SourceCode -> MVC -> ContactMvc4TB -> ContactMvc4TB -> Helpers -> DynamicDataType (hier findet man die Klassen, die Views und den Rest kann man dann selbst finden, wenn man sich das Projekt etwas anschaut. Ist alles ganz gut dokumentiert)

      Gefällt mir

      Antwort

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden / Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden / Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden / Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden / Ändern )

Verbinde mit %s