Verschiedenen Objekte aus einer Liste auf der Oberfläche anzeigen (Vererbung)

  • WPF

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Verschiedenen Objekte aus einer Liste auf der Oberfläche anzeigen (Vererbung)

    Hallo Zusammen,

    ich stehe gerade vor einem kleinen Problem. Ich bin momentan mit einem Projekt beschäftigt, bei welchem eine dynamische Oberfläche generiert werden soll.
    Man soll eine Art "Frage-Formular" entwerfen können. Dabei gibt es aber verschiedene "Muster".

    Ich kann jetzt zum Beispiel zu meinem Formular eine Frage hinzufügen, bei welcher dem Benutzer eine Textbox angezeigt wird und der Benutzer kann dann in diese Textbox seine Antwort eintragen.
    Es soll aber z.B. auch möglich sein eine Frage zu erstellen, bei welcher dem Benutzer dann z.B. eine Liste von Checkboxen angezeigt wird, wo er etwas anhaken muss.

    Das Klassen-Design im Hintergrund steht schon soweit. Dort gibt es eine Basis-Klasse und dann mehrere Klassen, welcher von der Basis-Klasse erben und somit die verschiedenen Fragemöglichkeiten darstellen.

    Mein Problem liegt jetzt leider bei der Erstellung der Oberfläche.
    Ich habe in meinem ViewModel eine ObservableCollection von meiner BasisKlasse und dort sind alle Frage-Objekte eingetragen.

    Jetzt muss ich die Oberfläche aber irgendwie dazu bringen, zwischen den einzelnen Typen zu unterscheiden.
    Dafür habe ich erstmal ein "ItemsControl" angelegt und den "ItemsSource" davon an meine Liste gebunden.
    Dann einen TextBlock erstellt und den TextBlock an die Frage gebunden. (Eine Frage gibt es ja immer. Und die Frage ist daher auch in der Basis-Klasse deklariert).

    So und nun beißts leider aus. Ich bräuchte eine Möglichkeit im XAML zwischen den Typen zu unterscheiden und dann zu sagen für diesen Typ soll das Item in meinem ItemsControl folgendes Layout haben (z.b. zwei Checkboxen angzeigen mit Ja/Nein) und für wieder einen anderen Typ, soll das Item aber ein ganz anderes Layout haben (z.B. einen "DateTimePicker", wo man ein gewisses Datum auswählen muss).

    Ich hoffe es gibt irgendeine Möglichkeit das relativ einfach umzusetzen.

    KillaChris schrieb:

    ch hoffe es gibt irgendeine Möglichkeit das relativ einfach umzusetzen.
    Jo, genau dafür sind DataTemplates in Kombination mit ContentPresenter vorgesehen:
    Im Viewmodel gibts eine allgemein gefasste Property vom Datentyp Object, und je nach Datentyp wendet der ContentPresenter ein anderes DataTemplate an.
    Allerdings weiß ich grad kein Tut, was sich speziell mit DataTemplates auseinandersetzt.

    Immerhin im Download von codeproject.com/Articles/85275…-visual-TabItem-States-Al habich neben einigem anderen auch einen ContentPresenter in Betrieb der in dieser Weise polymorph präsentiert.
    Erstmal danke für die schnelle Antwort.
    Ich hab mir gerade mal dein Beispiel angeschaut. Jetzt ist mir zumindestens schonmal klar geworden wie ich das Layout der verschiedenen Objekte festlegen kann.
    Wenn ich das richtig verstanden habe, dann erstelle ich für jeden Typ ein extra UserControl. (Dann habe ich zum Beispiel fünf UserControls und jedes Usercontrol kann seinen eigenen Typ darstellen).
    Das UserControl ist an der Stelle dann das DataTemplate, so legst du es in deinem BeispielProjekt ja auch fest:

    XML-Quellcode

    1. <DataTemplate>
    2. <my:uclPerson/>
    3. </DataTemplate>


    Das ist soweit alles klar.

    Das einzige was mich etwas stutzig macht ist der Satz von dir:

    Im Viewmodel gibts eine allgemein gefasste Property vom Datentyp Object, und je nach Datentyp wendet der ContentPresenter ein anderes DataTemplate an.


    Aber jetzt während dem Schreiben wird mir glaube ich auch klar was du damit meinst.

    Ich soll quasi im ViewModel eine Property anlegen und diese Property gibt dann das UserControl zurück (daher auch DatenTyp Object), welches als DataTemplate verwendet werden soll. Und im XAML kann ich im "<DataTemplate>" dann wieder eine Datenbindung anlegen und mich an diese Property binden. Dadurch sollte das Problem dann gelöst sein. (Sofern ich dich richtig verstanden habe?)
    fast richtig.
    Die Property gibt natürlich kein UserControl zurück, sondern irgendein Objekt, und dieses Objekt wird wohl einen deiner verschiedenen Datentypen haben.
    Aber der Return-Datentyp der Prop ist nicht ein bestimmter Datentyp, sondern einfach allgemen: Object.
    Damit du Objekte verschiedensten Datentyp reinpacken kannst.

    So.
    Und im Xaml bindest du den ContentPresenter daran, und gibst ihm zusätzlich verschiedene DataTemplates an die Hand, die je auf spezifische Typen passen.
    Dann - wenn du ein Dingens im Viewmodel in die Prop tust, updated das Binding den CP, und der sucht aus den ihm verfügbaren DataTemplate eines aus, was auf den Typen passt, der ihm über das Binding grad angedreht wurde.

    Und ja - ist meist sinnvoll, je Datentyp ein besonderes UserControls anzulegen, und dies dann in die DataTemplates einzubauen.
    Aber prinzipiell kann man die spezifische UI-Struktur auch direkt ins DataTemplate hineinbasteln - nur die können dadurch recht fett und unübersichtlich werden.
    Eine ContentPresenter ist überflüssig. Einfach die Items in eine CompositeCollection stecken, die DataTemplates als Ressourcen deklarieren und fertig. Siehe das Beispiel unten in verlinktem Artikel.
    UserControls können nützlich sein, funktionieren bei dieser Variante aber genauso gut.
    Ja. Ich hab im XAML in "<Window.Resources>" die DataTemplates definiert.
    Genau wie oben in dem Link beschrieben mit dem richtigen DatenTyp.

    z.B.

    XML-Quellcode

    1. <Window.Resources>
    2. <ResourceDictionary>
    3. <DataTemplate DataType="{x:Type loc:TextBoxQuestionViewModel}">
    4. <TextBlock Text="{Binding Name}"/>
    5. </DataTemplate>
    6. <DataTemplate DataType="{x:Type loc:DateQuestionViewModel}">
    7. <DatePicker SelectedDate="{Binding SelDate}"/>
    8. </DataTemplate>
    9. </ResourceDictionary>
    10. </Window.Resources>


    Und das ItemsControl ist dann so angelegt:

    XML-Quellcode

    1. <ItemsControl ItemsSource="{Binding Questions}"/>


    Und "Questions" ist eben eine Auflistung vom Objekt "BaseQuestionViewModel". "TextBoxQuestionViewModel" und "DateQuestionViewModel" erben von der Klasse "BaseQuestionViewModel".

    Für komplexere "Questions" kann ich dann aber auch wieder auf UserControls zurückgreifen. Da ich ja wie in deinem Beispiel oben auch einfach das UserControl in das DataTemplate reinstecken kann, dadurch ist das dann auch schön strukturiert und das XAML der Oberfläche nicht so überladen.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „KillaChris“ ()

    ups - habich überlesen, dass die Datatemplates auf die Item innerhalb der Listbox angewendet werden sollen. Da geht das, denn Listbox stellt intern für jedes Item einen ContentPresenter.

    Hatte iwie was gedacht mit links in Listbox anwählen, und rechts auf einem Panel einen ausführlichen DetailView des angewählten Objektes.