none
[WinRT] ObservableCollection Binding - Wie geht das? RRS feed

  • Frage

  • Hallo Leute,

    habe jetzt endlich mit Hilfe dieses Forums verstanden, wie ich eine ObservableCollection hinbekomme...

    Jetzt stehe ich vor dem nächsten Problem, ich möchte die Daten anzeigen - kriege das aber nicht hin...

    Jetzt zu den Details!

    Nehmen wir an, ich möchte eine App für Gesetzestexte programmieren und habe folgende ObservableCollection class:

    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Text;
    
    namespace Gestz.Model
    {
        public class GesetzElements
            {
    
            public GesetzElements()
                {
                //
                this.Item = new ObservableCollection<paragraph>();
                }
    
            private string _gesetzName;
            private int _paragraphNumber;
    
            public string gesetzName
                {
                get { return _gesetzName; }
                set { _gesetzName = value; }
                }
    
            public int paragraphNumber
                {
                get { return _paragraphNumber; }
                set { _paragraphNumber = value; }
                }
    
            public ObservableCollection<paragraph> Item { get; set; }
            }
    
    
        public class paragraph
            {
            private int _absatzNumber;
            private string _absatzText;
    
            public int absatzNumber
                {
                get { return _absatzNumber; }
                set { _absatzNumber = value; }
    
                }
    
            public string absatzText
                {
                get { return _absatzText; }
                set { _absatzText = value; }
                }
            }
    }
    

    Ich habe die Klasse für das Beispiel angepasst, müsst aber zu 99% identisch sein...

    Ich möchte jetzt auf meiner Page die Daten anzeigen, ich habe es erstmal mit einer Listview und einer Listbox probiert, kriege es aber nicht hin!

    Das ist die Page

    <Page x:Class="Gesetze.Optionen" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Gesetze" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid x:Name="LayoutRoot">

    <Button x:Name="AddParagraph" Content="Button" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Click="AddParagraph_click"/> <StackPanel> <ListView x:Name="lvTest" ItemsSource="{Binding Gesetze}"> <ListView.ItemTemplate> <DataTemplate> <TextBlock x:Name="txtData" Text="{Binding}" /> </DataTemplate> </ListView.ItemTemplate> </ListView> </StackPanel> </Grid> </Page>

    Wie gesagt sitze schon stunden da dran aber der will irgendwie nicht....

    Das ist der Code zur Page:

    using Gesetze.Common;
    using System;
    using Windows.ApplicationModel.Activation;
    using Windows.Storage.Pickers;
    using Windows.UI.Xaml;
    using Windows.UI.Xaml.Controls;
    using Windows.UI.Xaml.Navigation;
    using Gesetze.Model;
    using System.Collections.ObjectModel;
    
    
    namespace Gesetze
        {
            public sealed partial class Optionen :  Page, IFileOpenPickerContinuable
            {
            MainPage rootPage = MainPage.Current;
    
            public ObservableCollection<GesetzeElements> Paragraphen { get; set; }
    
            public Optionen()
                {
                this.InitializeComponent();
    
                this.Paragraphen = new ObservableCollection<GesetzeElements>();
    
                }
    
            
          [...]
    
    
            private void AddParagraph_click(object sender, RoutedEventArgs e)
                {
                var g = new GesetzeElements();
                g.Item.Add(new paragraph() { absatzNumber = 1, absatzText = "Absatz Nummer EINS!" });
                g.Item.Add(new paragraph() { absatzNumber = 2, absatzText = "Absatz Nummer ZWEI!" });
                g.Item.Add(new paragraph() { absatzNumber = 3, absatzText = "Absatz Nummer DREI!" });
                g.Item.Add(new paragraph() { absatzNumber = 4, absatzText = "Absatz Nummer VIER!" });
                Paragraphen.Add(g);
                this.DataContext = Paragraphen;
                
                }
            }
        }
    

    Ich wäre über ein paar Hilfestellungen sehr Dankbar!!!

    Gruß,

    Paul

    Donnerstag, 12. Februar 2015 22:41

Antworten

  • Hallo,
    willst du das komplette MVVM Pattern umsetzen oder erstmal nur die Grundlagen der Datenbindungen erarbeiten?
    Ich verzichte erstmal auf MVVM, wenn du dich näher damit befassen willst, findest du hier einen Blogbeitrag dazu. Dort erfährst du auch nochmal die Grundlagen zu Datenbindungen. Ich möchte hier daher nur deine Fehler aufzeigen.

    Mit das wichtigste ist der DataContext. Diesen setzt du am besten im Konstruktor noch vor InitialisizeComponent. In MVVM weißt man der Eigenschaft eine Instanz des Models zu. Ohne MVVM nimmt man häufig die Page-Klasse, das sieht dann so aus:

    public Optionen()
    {    
        this.Paragraphen = new ObservableCollection<GesetzElements>();
        this.DataContext = this;
        this.InitializeComponent();
    }

    Da die Page-Klasse und der DataContext die selbe Instanz sind, muss die OC als erstes initialisiert werden. Das hat den Hintergrund, dass sobald der DataContext zugewiesen wird, die Eigenschaften und ObservableCollections "abbonniert" werden um Änderungen mit zu bekommen. (Genauer werden bestimmte Events der jeweiligen Klassen abonniert.)

    Nun kann man innerhalb des XAML auf die öffentlichen Eigenschaften zugreifen, die im DataContext enthalten sind. Das ist in diesem Fall nur Paragraphen.

    <ListBox x:Name="lvTest" ItemsSource="{Binding Paragraphen}">

    Die List-Control-Klassen wie ListBox und ListView haben alle eine ItemTemplate-Eigenschaft. Innerhalb dieser Eigenschaft kann man bestimmen wie ein Item aussehen soll. Hier gilt nun nicht mehr der DataContext den wir der Seite zugewiesen haben. Statt dessen ist nun in jedem Item das jeweilige Element in der Auflistung der DataContext.

    Das hat zur Folge, das wir hier auf alle Eigenschaften der GesetzElements-Klasse zugreifen können. Es ist auch kein Problem eine weitere Liste darin zu verschachteln und darin wieder ein anderes ItemTemplate zu deklarieren:

    <ListBox x:Name="lvTest" ItemsSource="{Binding Paragraphen}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock x:Name="txtData" Text="{Binding gesetzName}" />
                    <ListBox Margin="20 0 0 0" Background="#202020" ItemsSource="{Binding Item}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding absatzText}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    Es ist ebenfalls möglich die ListBoxen nicht zu verschachteln. Wenn man in einer ListBox ein Element auswählt, wird es der SelectedItem-Eigenschaft des Controls zugewiesen. Darüber können wir nun eine 2. ListBox befüllen:
    <StackPanel Orientation="Horizontal">
        <ListBox x:Name="lvTest" ItemsSource="{Binding Paragraphen}" MinWidth="200">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock x:Name="txtData" Text="{Binding gesetzName}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox MinWidth="200" Margin="20 0 0 0" Background="#202020" ItemsSource="{Binding SelectedItem.Item, ElementName=lvTest}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding absatzText}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
    Beachte, dass du dafür natürlich gesetzName entsprechend zugewiesen haben solltest. Sonst werden nur leere Items dargestellt.

    Weiterhin solltest du dich an die allgemeinen Benennungskonventionen halten. Beispielsweise:

    • Öffentliche Eigenschaften werden groß geschrieben.
    • Versuche das denglisch zu vermeiden. Ich mag es schon nicht überhaupt etwas auf Deutsch zu benennen. Aber das englische Mehrzahl s an deutschen Wörtern oder Items für Elemente ist schon sehr verwirrend vermischt.
    • Da sind wir auch schon beim nächsten. Versuche Dinge möglichst aussagekräftig zu benennen. Item ist eines, da deutet nichts auf eine Liste hin. Besser wäre hier Items oder noch besser Paragraphs

    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Donnerstag, 12. Februar 2015 23:17
  • Vielen vielen Dank dir! 

    Gern geschehen :)

    Ich liebe diese Forum - hier wird man wenigstens mit seinem Problem ernst genommen...

    Genau das gefällt mir hier auch.

    Jetzt zu meiner 2. Frage...

    Wleches UI-Element eignet sich am besten für folgende Aufgabe:

    Ich will die einzelnen Absätze untereinander Auflisten:

    Links die Absatznummer - Rechts daneben den Text (Es sollen möglichst noch spalten "hinzufügbar" sein)

    Wenn ich drauf drücke-und-halte soll ich noch interagieren können z.B. über ein Flyout o.ä.

    Was wäre da sinnvoll?

    In XAML gibt es fürs Layout tausend Wege und wahrscheinlich würde jeder etwas anderes bevorzugen. Ich persönlich nutze am liebsten die zu Grunde liegenden Controls, die es auch auf anderen Plattformen gibt.

    Wenn dich tiefer gehend damit beschäftigen willst (was ich dir nur empfehlen kann), bietet die MSDN sehr viele Anlaufstellen. Unter anderem: Schnellstart: Hinzufügen von ListView- und GridView-Steuerelementen (XAML). Über die seitliche Navigationsleiste kannst du noch zu vielen verwanden Themen springen.

    Vom Grundsatz her kann man für dein Vorhaben gut eine ListView oder ListBox nehmen. Da kannst du das ItemTemplate frei gestalten und auch Spalten einfügen. Hier ein Beispiel:

    <DataTemplate>
        <Grid Width="500">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="150"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding absatzText}"/>
            <TextBlock Text="{Binding absatzNumber}" Grid.Column="1"/>
            <TextBlock Text="3. Spalte" Grid.Column="2"/>
        </Grid>
    </DataTemplate>
    Das kann man nach belieben anpassen. Auch andere Container wie das GridView könnten ganz interessant sein. Das steht alles in dem verlinkten MSDN Beitrag.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Freitag, 13. Februar 2015 01:52
  • Vielen vielen Dank dir! 

    Das mit dem denglish habe ich eigentlich auch nicht so gern - war jetzt leider ein Resultat aus dem anpassen für das Beipspiel - aber danke für die anderen Hinweise!

    Habe es eingebaut und erweitert und läuft!!!!

    Ich liebe diese Forum - hier wird man wenigstens mit seinem Problem ernst genommen...

    Jetzt zu meiner 2. Frage...

    Wleches UI-Element eignet sich am besten für folgende Aufgabe:

    Ich will die einzelnen Absätze untereinander Auflisten:

    Links die Absatznummer - Rechts daneben den Text (Es sollen möglichst noch spalten "hinzufügbar" sein)

    Wenn ich drauf drücke-und-halte soll ich noch interagieren können z.B. über ein Flyout o.ä.

    Was wäre da sinnvoll?


    • Bearbeitet PHep Freitag, 13. Februar 2015 01:22
    • Als Antwort markiert PHep Dienstag, 17. Februar 2015 22:17
    Freitag, 13. Februar 2015 01:10

Alle Antworten

  • Hallo,
    willst du das komplette MVVM Pattern umsetzen oder erstmal nur die Grundlagen der Datenbindungen erarbeiten?
    Ich verzichte erstmal auf MVVM, wenn du dich näher damit befassen willst, findest du hier einen Blogbeitrag dazu. Dort erfährst du auch nochmal die Grundlagen zu Datenbindungen. Ich möchte hier daher nur deine Fehler aufzeigen.

    Mit das wichtigste ist der DataContext. Diesen setzt du am besten im Konstruktor noch vor InitialisizeComponent. In MVVM weißt man der Eigenschaft eine Instanz des Models zu. Ohne MVVM nimmt man häufig die Page-Klasse, das sieht dann so aus:

    public Optionen()
    {    
        this.Paragraphen = new ObservableCollection<GesetzElements>();
        this.DataContext = this;
        this.InitializeComponent();
    }

    Da die Page-Klasse und der DataContext die selbe Instanz sind, muss die OC als erstes initialisiert werden. Das hat den Hintergrund, dass sobald der DataContext zugewiesen wird, die Eigenschaften und ObservableCollections "abbonniert" werden um Änderungen mit zu bekommen. (Genauer werden bestimmte Events der jeweiligen Klassen abonniert.)

    Nun kann man innerhalb des XAML auf die öffentlichen Eigenschaften zugreifen, die im DataContext enthalten sind. Das ist in diesem Fall nur Paragraphen.

    <ListBox x:Name="lvTest" ItemsSource="{Binding Paragraphen}">

    Die List-Control-Klassen wie ListBox und ListView haben alle eine ItemTemplate-Eigenschaft. Innerhalb dieser Eigenschaft kann man bestimmen wie ein Item aussehen soll. Hier gilt nun nicht mehr der DataContext den wir der Seite zugewiesen haben. Statt dessen ist nun in jedem Item das jeweilige Element in der Auflistung der DataContext.

    Das hat zur Folge, das wir hier auf alle Eigenschaften der GesetzElements-Klasse zugreifen können. Es ist auch kein Problem eine weitere Liste darin zu verschachteln und darin wieder ein anderes ItemTemplate zu deklarieren:

    <ListBox x:Name="lvTest" ItemsSource="{Binding Paragraphen}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock x:Name="txtData" Text="{Binding gesetzName}" />
                    <ListBox Margin="20 0 0 0" Background="#202020" ItemsSource="{Binding Item}">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <TextBlock Text="{Binding absatzText}"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    Es ist ebenfalls möglich die ListBoxen nicht zu verschachteln. Wenn man in einer ListBox ein Element auswählt, wird es der SelectedItem-Eigenschaft des Controls zugewiesen. Darüber können wir nun eine 2. ListBox befüllen:
    <StackPanel Orientation="Horizontal">
        <ListBox x:Name="lvTest" ItemsSource="{Binding Paragraphen}" MinWidth="200">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock x:Name="txtData" Text="{Binding gesetzName}" />
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <ListBox MinWidth="200" Margin="20 0 0 0" Background="#202020" ItemsSource="{Binding SelectedItem.Item, ElementName=lvTest}">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding absatzText}"/>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </StackPanel>
    Beachte, dass du dafür natürlich gesetzName entsprechend zugewiesen haben solltest. Sonst werden nur leere Items dargestellt.

    Weiterhin solltest du dich an die allgemeinen Benennungskonventionen halten. Beispielsweise:

    • Öffentliche Eigenschaften werden groß geschrieben.
    • Versuche das denglisch zu vermeiden. Ich mag es schon nicht überhaupt etwas auf Deutsch zu benennen. Aber das englische Mehrzahl s an deutschen Wörtern oder Items für Elemente ist schon sehr verwirrend vermischt.
    • Da sind wir auch schon beim nächsten. Versuche Dinge möglichst aussagekräftig zu benennen. Item ist eines, da deutet nichts auf eine Liste hin. Besser wäre hier Items oder noch besser Paragraphs

    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Donnerstag, 12. Februar 2015 23:17
  • Vielen vielen Dank dir! 

    Das mit dem denglish habe ich eigentlich auch nicht so gern - war jetzt leider ein Resultat aus dem anpassen für das Beipspiel - aber danke für die anderen Hinweise!

    Habe es eingebaut und erweitert und läuft!!!!

    Ich liebe diese Forum - hier wird man wenigstens mit seinem Problem ernst genommen...

    Jetzt zu meiner 2. Frage...

    Wleches UI-Element eignet sich am besten für folgende Aufgabe:

    Ich will die einzelnen Absätze untereinander Auflisten:

    Links die Absatznummer - Rechts daneben den Text (Es sollen möglichst noch spalten "hinzufügbar" sein)

    Wenn ich drauf drücke-und-halte soll ich noch interagieren können z.B. über ein Flyout o.ä.

    Was wäre da sinnvoll?


    • Bearbeitet PHep Freitag, 13. Februar 2015 01:22
    • Als Antwort markiert PHep Dienstag, 17. Februar 2015 22:17
    Freitag, 13. Februar 2015 01:10
  • Vielen vielen Dank dir! 

    Gern geschehen :)

    Ich liebe diese Forum - hier wird man wenigstens mit seinem Problem ernst genommen...

    Genau das gefällt mir hier auch.

    Jetzt zu meiner 2. Frage...

    Wleches UI-Element eignet sich am besten für folgende Aufgabe:

    Ich will die einzelnen Absätze untereinander Auflisten:

    Links die Absatznummer - Rechts daneben den Text (Es sollen möglichst noch spalten "hinzufügbar" sein)

    Wenn ich drauf drücke-und-halte soll ich noch interagieren können z.B. über ein Flyout o.ä.

    Was wäre da sinnvoll?

    In XAML gibt es fürs Layout tausend Wege und wahrscheinlich würde jeder etwas anderes bevorzugen. Ich persönlich nutze am liebsten die zu Grunde liegenden Controls, die es auch auf anderen Plattformen gibt.

    Wenn dich tiefer gehend damit beschäftigen willst (was ich dir nur empfehlen kann), bietet die MSDN sehr viele Anlaufstellen. Unter anderem: Schnellstart: Hinzufügen von ListView- und GridView-Steuerelementen (XAML). Über die seitliche Navigationsleiste kannst du noch zu vielen verwanden Themen springen.

    Vom Grundsatz her kann man für dein Vorhaben gut eine ListView oder ListBox nehmen. Da kannst du das ItemTemplate frei gestalten und auch Spalten einfügen. Hier ein Beispiel:

    <DataTemplate>
        <Grid Width="500">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="50" />
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="150"/>
            </Grid.ColumnDefinitions>
            <TextBlock Text="{Binding absatzText}"/>
            <TextBlock Text="{Binding absatzNumber}" Grid.Column="1"/>
            <TextBlock Text="3. Spalte" Grid.Column="2"/>
        </Grid>
    </DataTemplate>
    Das kann man nach belieben anpassen. Auch andere Container wie das GridView könnten ganz interessant sein. Das steht alles in dem verlinkten MSDN Beitrag.


    Tom Lambert - .NET (C#) MVP
    Wozu Antworten markieren und für Beiträge abstimmen? Klicke hier.
    Nützliche Links: .NET Quellcode | C# ↔ VB.NET Konverter | Account bestätigen (Verify Your Account)
    Ich: Webseite | Code Beispiele | Facebook | Twitter | Snippets

    Freitag, 13. Februar 2015 01:52
  • Wieder was gelernt - und ich hoffe auch soweit verstanden. Zumindest funktioniert es!

    Vielen vielen Dank!!!

    Freitag, 13. Februar 2015 22:39