none
Control mit Binding zu komplexen Datenstrukturen RRS feed

  • Frage

  • Hi,

    ich habe eine Textbox, welche an ein komplexeres Datenobjekt gebunden ist. Leider wird nicht der richtige Inhalt angezeigt, besser gesagt, es wird nichts angezeigt.

    Da ich bis jetzt nur die Anbindung an Properties erster Ordnung kenne
    ( z.B. Text="{Binding Path=Color}" )
    bin ich mir nicht sicher, ob ich das im xaml richtig formuliere. So sieht es bei mir aus:

    Text="{Binding Path=data.HauptKlasse.ListOfUnterklassen[data.HauptKlasse.IdOfListUnterklassen].Color}"

    Der Pfad data.HauptKlasse.ListOfUnterklassen[data.HauptKlasse.IdOfListUnterklassen].Color gibt auf jeden Fall einen Wert zurück, das habe ich im codebehind getestet und den Pfad mit copy+paste übernommen, der ist also fehlerfrei.

    Warum wird der Inhalt von Color nicht in der TextBox angezeigt?

    Bei Bedarf sende ich noch die anderen Quelltexte (xaml, codebehind, Klassen Hauptklasse und Unterklasse), aber ich gehe davon aus, dass diese nicht relevant sind.

    Frank


    www.energiewende-mach-ich-selbst.de

    Dienstag, 24. Juni 2014 14:52

Antworten

  • Hallo,
    Ich vermute mal, das der Bindungsausdruck nichts mit Indexern anfangen kann, die ebenfalls gebunden sind. So einfach wird es also nicht.

    Ich habe nun 3 Ideen wie du es stattdessen machen könntest:

    1. Statt der Eigenschaft IdOfListUnterklassen kannst du eine Eigenschaft implementieren, die dir direkt das Objekt aus ListOfUnterklassen zurück gibt. Als Außenstehender sehe ich darin keine Nachteile.
      Im XAML kannst du dann die Eigenschaften durch einen Punkt (.) abgrenzen:
      Text="{Binding Path=data.HauptKlasse.UnterklassenObjekt.Color}"
    2. Erzeuge einen Konverter, dem du die Daten des Ausdrucks übergibst. Der Converter verarbeitet dann im Codebehind die Infos und liefert das Richtige Objekt zurück. Durch die ConvertBack-Methode kannst du das auch wieder zurück in Hauptklasse schreiben.
      Ein einfacher Converter müsste einen Parser für einen String o.ä. haben um das Objekt zu finden. Ein MultiBinding dagegen kann mehrere Bindungen und Resourcen-Bindungen (Statische Werte wie Namen) entgegen nehmen. Beim Zurückkonvertieren müsstest du allerdings wieder über den ConvertParameter arbeiten. (Der Parameter kann aber auch ein eigenes Objekt mit mehreren Eigenschaften sein.)
      Mehr dazu unter: IValueConverter-Schnittstelle und IMultiValueConverter-Schnittstelle.
    3. Wenn du eine Liste von Objekten hast, dann werden diese Objekte i.d.R. auf die gleiche Art und Weise in der GUI angezeigt. Es bietet sich darum an, eine Liste an die Auflistung zu binden und darin die Items mit dem eigentlichen XAML zu befüllen:
      <ItemsControl ItemsSource="{Binding data.Hauptklasse.ListOfUnterklassen}">
          <ItemsControl.ItemsPanel>
              <ItemsPanelTemplate>
                  <!--In diesem Container werden die Elemente angeordnet-->
                  <StackPanel/>
              </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>
          <ItemsControl.ItemTemplate>
              <DataTemplate>
                  <!--So sieht ein Element aus-->
                  <Grid>
                      <TextBox Margin="10" Height="25" Text="{Binding Color}" />
                  </Grid>
              </DataTemplate>
          </ItemsControl.ItemTemplate>
      </ItemsControl>
      Beachte dabei, das wirklich alle Elemente der Auflistung angezeigt werden. Du könntest höchstens die Bindung von ItemsSource über einen Converter beeinflussen.

    Mein Favorit ist Lösung 1. Lösung 2 würde ich, wenn möglich vermeiden. Nr. 3 ist dann am Besten, wenn du wirklich ganze Liste darstellen willst.


    Tom Lambert - C# MVP
    Bitte bewertet- und markiert Beiträge als Antwort. Danke.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert frank me Mittwoch, 9. Juli 2014 07:05
    Dienstag, 24. Juni 2014 18:47
    Moderator

Alle Antworten

  • Hallo,
    Ich vermute mal, das der Bindungsausdruck nichts mit Indexern anfangen kann, die ebenfalls gebunden sind. So einfach wird es also nicht.

    Ich habe nun 3 Ideen wie du es stattdessen machen könntest:

    1. Statt der Eigenschaft IdOfListUnterklassen kannst du eine Eigenschaft implementieren, die dir direkt das Objekt aus ListOfUnterklassen zurück gibt. Als Außenstehender sehe ich darin keine Nachteile.
      Im XAML kannst du dann die Eigenschaften durch einen Punkt (.) abgrenzen:
      Text="{Binding Path=data.HauptKlasse.UnterklassenObjekt.Color}"
    2. Erzeuge einen Konverter, dem du die Daten des Ausdrucks übergibst. Der Converter verarbeitet dann im Codebehind die Infos und liefert das Richtige Objekt zurück. Durch die ConvertBack-Methode kannst du das auch wieder zurück in Hauptklasse schreiben.
      Ein einfacher Converter müsste einen Parser für einen String o.ä. haben um das Objekt zu finden. Ein MultiBinding dagegen kann mehrere Bindungen und Resourcen-Bindungen (Statische Werte wie Namen) entgegen nehmen. Beim Zurückkonvertieren müsstest du allerdings wieder über den ConvertParameter arbeiten. (Der Parameter kann aber auch ein eigenes Objekt mit mehreren Eigenschaften sein.)
      Mehr dazu unter: IValueConverter-Schnittstelle und IMultiValueConverter-Schnittstelle.
    3. Wenn du eine Liste von Objekten hast, dann werden diese Objekte i.d.R. auf die gleiche Art und Weise in der GUI angezeigt. Es bietet sich darum an, eine Liste an die Auflistung zu binden und darin die Items mit dem eigentlichen XAML zu befüllen:
      <ItemsControl ItemsSource="{Binding data.Hauptklasse.ListOfUnterklassen}">
          <ItemsControl.ItemsPanel>
              <ItemsPanelTemplate>
                  <!--In diesem Container werden die Elemente angeordnet-->
                  <StackPanel/>
              </ItemsPanelTemplate>
          </ItemsControl.ItemsPanel>
          <ItemsControl.ItemTemplate>
              <DataTemplate>
                  <!--So sieht ein Element aus-->
                  <Grid>
                      <TextBox Margin="10" Height="25" Text="{Binding Color}" />
                  </Grid>
              </DataTemplate>
          </ItemsControl.ItemTemplate>
      </ItemsControl>
      Beachte dabei, das wirklich alle Elemente der Auflistung angezeigt werden. Du könntest höchstens die Bindung von ItemsSource über einen Converter beeinflussen.

    Mein Favorit ist Lösung 1. Lösung 2 würde ich, wenn möglich vermeiden. Nr. 3 ist dann am Besten, wenn du wirklich ganze Liste darstellen willst.


    Tom Lambert - C# MVP
    Bitte bewertet- und markiert Beiträge als Antwort. Danke.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    • Als Antwort markiert frank me Mittwoch, 9. Juli 2014 07:05
    Dienstag, 24. Juni 2014 18:47
    Moderator
    1. Statt der Eigenschaft IdOfListUnterklassen kannst du eine Eigenschaft implementieren, die dir direkt das Objekt aus ListOfUnterklassen zurück gibt. Als Außenstehender sehe ich darin keine Nachteile.
      Im XAML kannst du dann die Eigenschaften durch einen Punkt (.) abgrenzen:
      Text="{Binding Path=data.HauptKlasse.UnterklassenObjekt.Color}"

    Mir gefällt Variante 1 auch am besten. Allerdings ...

    Das Objekt data deserialisiere ich aus einer xml.

    Nun könnte ich ein neues Objekt erstellen, welches die Daten aus data nach dataCopy in einer eigenen Methode transferiert und aus z.B:
    data.HauptKlasse.ListOfUnterklassen[data.HauptKlasse.IdOfListUnterklassen].Color
    dann
    data.HauptKlasse.UnterklassenObjekt.Color
    macht. Aber das ist vielleicht ein wenig sehr overhead.

    Oder ich erweitre das data-Objekt (die Data-Klasse) mit HauptKlasse.UnterklassenObjekt.Color. Aber dann habe ich sehr viele Doppelungen, die dann auch mit zu einer xml serialisiert werden (müssen).

    Das Property Color war nur ein Beispiel, um mein Anliegen zu erklären. Insgesamt enthält mein data-Objekt evtl. 300 Properties, von denen ich jeweils ca. 50 Stück brauche.

    Wäre es vielleicht eine Lösung, data.HauptKlasse.ListOfUnterklassen[data.HauptKlasse.IdOfListUnterklassen].Color software-seitig an das Control zu binden? Welche Ideen habt ihr dazu?


    www.energiewende-mach-ich-selbst.de

    • Als Antwort markiert frank me Mittwoch, 9. Juli 2014 07:04
    • Tag als Antwort aufgehoben frank me Mittwoch, 9. Juli 2014 07:05
    Freitag, 27. Juni 2014 12:08
  • Hallo,
    ich glaube egal welche Lösung du am Ejde nimmst - es wird immer relativ komplex werden. Das liegt aber einfach der großen Datenstruktur.

    Wäre es vielleicht eine Lösung, data.HauptKlasse.ListOfUnterklassen[data.HauptKlasse.IdOfListUnterklassen].Color software-seitig an das Control zu binden? Welche Ideen habt ihr dazu?

    Solange der Index unveränderlich ist, geht das ohne Probleme:

    textBlock1.SetBinding(TextBlock.TextProperty, new Binding("Color") { Source = data.Hauptklasse.ListOfUnterklassen[data.Hauptklasse.IdOfListUnterklassen] });
    Du kannst auch noch Mode auf TwoWay setzen. Die Bindung funktioniert wie im XAML, nur das du hier den Vorteil hast, den Indexer einsetzen zu können.


    Tom Lambert - C# MVP
    Bitte bewertet- und markiert Beiträge als Antwort. Danke.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Freitag, 27. Juni 2014 14:25
    Moderator
  • Ich habe Lösung Nr. 1 umgesetzt.

    Danke!


    www.energiewende-mach-ich-selbst.de

    Mittwoch, 9. Juli 2014 07:05