C# DataBinding - Collection an GridView binden

Krik

Fleet Admiral
Registriert
Juni 2005
Beiträge
14.286
Moin,

ich habe eine Klasse RSSFeed geschrieben, die eine Liste RSSItems beinhaltet.
Diese Liste will ich in einem GridView in einer Metro-App für Windows 8 ausgeben.

Die Sache ist aber, ich bekomme die Bindung irgendwie nicht hin.

XAML (relevanter Teil):
Code:
<GridView Grid.Column="0" Grid.Row="1" x:Name="NewsFeedGridView" DataContext="{Binding Source=App.NewsFeed.Items}">
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid Height="110" Width="480" Margin="10" UseLayoutRounding="True">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Border Background="White" Width="110" Height="110">
                    <!-- <Image Source="{Binding Image}" Stretch="Uniform" HorizontalAlignment="Center" VerticalAlignment="Center"/> -->
                </Border>
                <StackPanel Grid.Column="1" VerticalAlignment="Top" Margin="10,0,0,0">
                    <TextBlock Text="{Binding Path=Title}" Style="{StaticResource TitleTextStyle}"/>

                    <Grid>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="Auto"/>
                            <ColumnDefinition Width="*"/>
                        </Grid.ColumnDefinitions>

                        <TextBlock Grid.Column="0" Text="{Binding PubDate}" Style="{StaticResource ItemTextStyle}" TextWrapping="NoWrap"/>
                        <TextBlock Grid.Column="1" Text="von" Style="{StaticResource CaptionTextStyle}" TextWrapping="NoWrap" Margin="5,0,3,0"/>
                    </Grid>

                    <TextBlock Text="{Binding Description}" Style="{StaticResource BodyTextStyle}" MaxHeight="60"/>

                </StackPanel>
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</GridView>

App.xaml.cs
Code:
public static RSSFeed NewsFeed;
public static RSSFeed ArticleFeed;
public static RSSFeed DownloadFeed;

public App()
{
    this.InitializeComponent();
    this.Suspending += OnSuspending;
    NewsFeed = new RSSFeed(new Uri("https://www.computerbase.de/rss/news.xml"));
    ArticleFeed = new RSSFeed(new Uri("https://www.computerbase.de/rss/artikel.xml"));
    DownloadFeed = new RSSFeed(new Uri("https://www.computerbase.de/rss/downloads.xml"));
}

usw.

RSSFeed.cs
Code:
public class RSSFeed : INotifyPropertyChanged
{
    private string _title;
    private Uri _link;
    private string _description;
    private List<RSSItem> _items { get; set; }
    private DateTime _lastUpdate = new DateTime();
    private int _maxItems = 25;
    public event PropertyChangedEventHandler PropertyChanged;

usw.

RSSItem.cs
Code:
public class RSSItem : INotifyPropertyChanged
{
    private string _title;
    private DateTime _pubDate;
    private string _description;
    private Uri _link;
    private string _ID;
    private bool _isNew;
    public event PropertyChangedEventHandler PropertyChanged;

usw.

Alles was Unterstriche hat, hat Getter und Setter, um an die Werte zu kommen.

Woran liegt das jetzt, das nichts angezeigt wird?

Gruß, Laurin
 

Anhänge

  • Unbenannt.png
    Unbenannt.png
    19,5 KB · Aufrufe: 278
Zuletzt bearbeitet:
Spontan kommt es mir etwas komisch vor, die DataItems in die App-Klasse zu legen und als statisch zu markieren; das hab ich noch nie so gemacht (ich hatte aber bislang auch noch nichts mit Metro zu tun, vielleicht soll es dort ja so sein). Bekommst Du im Ausgabefenster von Visual Studio keine Fehler wegen Data Binding angezeigt?
Eventuell musst Du dafür den Error Level hochsetzen: http://blogs.msdn.com/b/wpfsldesign...ings-in-a-wpf-or-silverlight-application.aspx
 
Ich hab das einfach aus praktischen Gründen dorthin gelegt. Das erspart mir etwas Kopfzerbrechen.

Ich habe das Error Level von der Stufe "Fehler" auf "Ausführlich" gestellt, aber das hat leider nicht geholfen. Laut dem Debugger ist alles rechtens.
 
Dein Problem ist List<T>. Eine Liste implementiert nicht INotifyPropertyChanged. Du musst eine ObservableCollection<T> benutzen.

Nichtsdestotrotz, ich erdreiste mir ein paar Worte zu deinem Code.

Code:
private List<RSSItem> _items { get; set; }
Das ist Mumpitz. Was soll ein private Property dir bringen?

Code:
public static RSSFeed NewsFeed;
public static RSSFeed ArticleFeed;
public static RSSFeed DownloadFeed;
Wurde schon erwähnt. Ebenfalls Mumpitz. Du machst hier etwas static, weil du sonst nicht weißt, wie du an die Daten kommst oder wie ist das mit dem Kopfzerbrechen zu verstehen?

Schau dir mal die Metro-Templates an.
Für eine Page solltest du von LayoutAwarePage ableiten. Die Klasse bringt auch ein Dict für ViewModel mit. Für deine Datenobjekte leite von BindableBase ab. Die Klasse implementiert INotifyPropertyChanged, sowie allen Kram drumherum, z.B. die Methode SetProperty (macht dir das Leben einfacher).
 
Hast du denn INotifyPropertyChanged auch richtig implementiert?
Also wird das Event auch gefeuert, wenn die Attribute per Setter verändert werden?
(sorry für die dämliche Frage, aber das fehlt in dem Code den du gepostet hast)

Außerdem benutzt du ne einfache List<RSSItem>, weswegen das Grid garnicht mitbekommt, wenn RSSItems hinzugefügt werden.
Da hilfts auch nix INotifyPropertyChanged zu implementieren, denn das Event würde ja nur gefeuert werden, wenn der Items Property ne neue Liste zugewiesen wird.
Per BindingList<RSSItem> könntest du das Problem umgehen.

Generell machst du aber imo etwas falsch.
So wie du versuchst die Daten zu binden, hat man das unter WindowsForms gemacht.

Unter WPF/Silverlight gibts da nen anderen Ansatz.
Schau dir mal hier die Antwort an: klick

Edit:
uh da war ich wohl etwas langsam...
 
holy schrieb:
Dein Problem ist List<T>. Eine Liste implementiert nicht INotifyPropertyChanged. Du musst eine ObservableCollection<T> benutzen.
Verdammt, das habe ich nicht beachtet. Uff, da muss ich einiges umbauen.

holy schrieb:
Was soll ein private Property dir bringen?
Ups, das ist ein Rest vom vorherigen Code. Das hätte da gar nicht mehr so stehen sollen.

holy schrieb:
Du machst hier etwas static, weil du sonst nicht weißt, wie du an die Daten kommst oder wie ist das mit dem Kopfzerbrechen zu verstehen?
Kopfzerbrechen = Faulheit. ;)
Ich erspare es mir, die Referenzen zu übergeben, wenn ich von einer Seite auf die nächste umschalte.

holy schrieb:
Da muss ich mich erst einlesen, was mir das bringt. Bei dem Umfang von .Net, WPF usw. bin ich noch nicht an allem vorbeigekommen.

Grantig schrieb:
Hast du denn INotifyPropertyChanged auch richtig implementiert?
Also wird das Event auch gefeuert, wenn die Attribute per Setter verändert werden?
(sorry für die dämliche Frage, aber das fehlt in dem Code den du gepostet hast)
Ich kann die Frage verstehen.

Hier mal beispielsweise für das Description-Property. Bei den anderen Propertys hab ich es ähnlich gemacht:
Code:
public string Description
{
    get
    {
        return _description;
    }
    set
    {
        if (value != null && value.Length > 0)
        {
            _description = value;
            NotifyPropertyChanged("Description");
        }
    }
}
Code:
public event PropertyChangedEventHandler PropertyChanged;

private void NotifyPropertyChanged(String info)
{
    if (PropertyChanged != null)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(info));
    }
}
Ich wollte nur nicht alles posten, weil der Code mittlerweile mehrere Seiten Umfang hat.


Grantig schrieb:
Generell machst du aber imo etwas falsch.
So wie du versuchst die Daten zu binden, hat man das unter WindowsForms gemacht.
Ich habe noch ein Problem damit, das DataBinding komplett zu durchschauen. Ich weiß, wie es vom Konzept her funktionieren soll, aber ich habe Probleme damit das selber einzusetzen. Darum frage ich ja hier, was ich falsch mache.


Vielen Dank für eure bisherigen Antworten! :)
 
Was dir noch fehlt, um das DataBinding in deiner XAML Datei auch korrekt hinzubekommen, ist das Setzen des DataContext. Das kannst du z. B. im Code-Behind deiner XAML Datei machen. Im Konstruktor kannst du dann den DataContext der XAML Seite auf die Instanz deiner Klasse setzen, die die Eigenschaften für die Bindings anbietet.


Gruß, Bahiera
 
Noch eine völlig anders gelegene Sache: Ist dein RSS Feed Implementierung eine Eigenentwicklung? Denn seit net 3.5 gibt es den SyndicationFeed der dir schon einen Großteil der Arbeit abnimmt...
 
Ich seh grade, du hast auch einen Fehler in deinem XAML.
Code:
<GridView Grid.Column="0" Grid.Row="1" x:Name="NewsFeedGridView" DataContext="{Binding Source=App.NewsFeed.Items}">

Die Items sind nicht dein DataContext, sondern ItemsSource
Code:
<GridView Grid.Column="0" Grid.Row="1" x:Name="NewsFeedGridView" ItemsSource="{Binding Source=App.NewsFeed.Items}">
 
@Mike
SyndicationFeed verwende ich zur Abfrage und Auswertung des RSS Feeds. Genial Sache! Früher habe ich immer meinen eigenen Parser für so etwas geschrieben.


So, jetzt muss ich mir noch ein paar Dinge zu Data Binding durchlesen. Worin nun der Unterschied zwischen DataContext und ItemSource ist, ist mir noch nicht klar.
 
Hallo ,

Ich zitiere aus Galileo Computing Visual C# 2010 Das Umfassende Handbuch.

Die Klasse DataContext kann man sich als Bindeglied zwischen der eigentlichen Datenquelle und den bindenden Steuerelementen vorstellen. DataContext stellt die Daten bereit; das Steuerelement weiß aber noch nicht, welche es anzeigen soll.

Jedes von FrameworkElement abgeleitete Steuerelement verfügt über die Eigenschaft DataContext. Darüber wird die Datenquelle festgelegt, die bei Verwendung des Binding-Objekts verwendet werden soll. Sie können mit

und nun noch was zu ItemsSource...auch aus diesem Buch.

Diese Eigenschaft bietet die Möglichkeit der Anbindung von Objektmengen. Grundsätzlich lässt sich jede Objektmenge anbinden, vorausgesetzt, diese implementiert die Schnittstelle IEnumerable. Das gilt nicht nur für ObservableCollection<T>, sondern auch gleichermaßen für ArrayList, List<T> und jedes klassische Array.


Hoffe das hilft dir weiter.

MFG
Ergänzung ()

Du kannst natürlich beide verwenden, zb Datacontext von deinem Container, zb. das Grid, auf dem du die Referenz auf deine anzubindende Collection legst und Itemsscource zb die untergeordneten Collections der Hauptcollection oder einfach nur ItemsSource="{Binding}" wenn du an die Hauptcollection binden möchtest.

mfg
Ergänzung ()

Es ist immer empfehlenswert die Referenz auf deine Quelle an den DataContext eines Containers zu binden, entweder in codebehind oder in Xaml und dann das Binding von einfachen Elementen mit Binding Path an die Content Eigenschaft oder Text oder Displaymemberbinding Eigenschaft zu binden je nachdem an welches Element du binden möchtest und zb bei einem Treeview oder Listview dann eine Liste (observablecollection) an die itemsscource Eigenschaft binden.
 
Vielen Dank für deine Hinweise. :)

Allerdings ist das Thema nicht mehr aktuell. Schau mal auf's Datum. ;)
 
Lach , weiß auch nicht wo ich das ausgegraben hab, hab gar nicht auf das Datum geschaut ;-).
 
Zurück
Oben