WP7 - ListBox Bindung an verschachtelten ObservableCollection
Ich habe eine ObservableCollection
von Objekten wie folgt:
public class UserDataViewModel
{
private ObservableCollection<CategoryItem> _data =
new ObservableCollection<CategoryItem>();
public ObservableCollection<CategoryItem> Data
{
get { return _data; }
private set { }
}
//Other methods to set Data
}
Den CategoryItem
Klasse ist definiert als:
public class CategoryItem : INotifyPropertyChanged
{
private string _name = null;
private ObservableCollection<EntryItem> _entries =
new ObservableCollection<EntryItem>();
public string Name
{
get { return _name; }
set {
if( value != _name ) {
_name = value;
NotifyPropertyChanged( "Name" );
}
}
}
public ObservableCollection<EntryItem> Entries
{
get { return _entries; }
set {
if( value != _entries ) {
_entries = value;
NotifyPropertyChanged( "Entries" );
}
}
}
//INotifyPropertyChanged code follows
}
Den EntryItem
Klasse ist definiert als:
public class EntryItem : INotifyPropertyChanged
{
private string _name = null;
public string Name
{
get { return _name; }
set {
if( value != _name ) {
_name = value;
NotifyPropertyChanged( "Name" );
}
}
}
//INotifyPropertyChanged code follows
}
Ich versuche, binden diese zu einem ListBox
. Jeder ListBoxItem
besteht aus 2 TextBlock
s. Ich will die erste TextBlock
zur Anzeige der EntryItem.Name
- Eigenschaft und der zweite für die Anzeige der CategoryItem.Name
Eigenschaft. Hier ist, was ich versucht habe in XAML (ohne Erfolg):
<ListBox x:Name="MyListBox"
Margin="0,0,-12,0"
ItemsSource="{Binding Data}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Margin="0,0,0,17">
<!--This should display EntryItem.Name-->
<TextBlock Text="{Binding Entries.Name}"
TextWrapping="Wrap"
Margin="12,0,0,0"
Style="{StaticResource PhoneTextExtraLargeStyle}" />
<!--This should display CategoryItem.Name-->
<TextBlock Text="{Binding Name}"
TextWrapping="Wrap"
Margin="12,-6,0,0"
Style="{StaticResource PhoneTextSubtleStyle}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In der code-behind für diese Seite bin ich-Einstellung:
DataContext = App.ViewModel; //ViewModel is of type UserDataViewModel
Bekomme ich immer wieder die binding-Fehler:
System.Windows.Data Error: BindingExpression path error: 'Name' property not found on 'System.Collections.ObjectModel.ObservableCollection`1[NestedCollection.ViewModels.EntryItem]' 'System.Collections.ObjectModel.ObservableCollection`1[NestedCollection.ViewModels.EntryItem]' (HashCode=123081170). BindingExpression: Path='Entries.Name' DataItem='NestedCollection.ViewModels.CategoryItem' (HashCode=121425257); target element is 'System.Windows.Controls.TextBlock' (Name=''); target property is 'Text' (type 'System.String')..
NestedCollection
ist der name dieses Projekts und aller oben genannten Klassen sind in der NestedCollection.ViewModels
namespace.
Nur den Inhalt der zweiten TextBlock
angezeigt werden. Wie kann ich dieses Problem beheben?
Danke für deine Hilfe, das hat mich verrückt für ein paar Stunden jetzt!
EDIT:
Angenommen, die Data
Sammlung enthält 2 Einträge, "Credit Cards" und "E-Mail-Konten" (diese sind Name
Eigenschaft jedes CategoryItem
Objekt in der Sammlung. Sagen, der erste CategoryItem
hat die EntryItem
Objekte "Visa", "Mastercard" und "American Express", und die zweite CategoryItem
Objekt hat EntryItem
Objekte "Google Mail" und "Hotmail", dann möchte ich die ListBox
anzeigen:
Visa
Credit Cards
Mastercard
Credit Cards
American Express
Credit Cards
GMail
Email Accounts
Hotmail
Email Accounts
Merke ich, dass der Entries
Eigenschaft von Data
keinen Name
Eigenschaft, jeden Eintrag innerhalb es spielt. Es ist trotzdem ein index in die Entries
im XAML binden?
Du musst angemeldet sein, um einen Kommentar abzugeben.
Sie versuchen, Sie zu binden eine
ObservableCollection<T>
zu einemTextBox
. Denken Sie über es.ObservableCollection<EntryItem>
nicht über eine Eigenschaft namensName
.EntryItem
Klasse.Ich schlage vor, Sie verwenden eine
ItemsControl
statt, oder verwenden Sie eineConverter
zu konvertierenEntryItem
Namen in einen Komma-separierten string.Nach einem Blick auf dein edit:
Versuchen folgenden code:
--EDIT--
Sieht aus wie es ist ein bekanntes problem in
Silverlight 3
.http://forums.silverlight.net/forums/p/108804/280986.aspx
Zu umgehen, dass entweder eine Referenz
CategoryItem
imEntryItem
namensParent
oder etwas ähnliches, um es aufzurufen.Oder, wie beschrieben in den link oben, legte Ihre
DataTemplate
in eineUserControl
für Sie zu arbeiten.Converter
zu konvertieren in ein CSV-string, wie soll ich binden? Sorry, wenn es dumme Frage, ich bin neu in C# und Bindungen. Ich habe bearbeitet die Frage, um es klar.To workaround that, either put a reference of CategoryItem in EntryItem named Parent or something similar to access it.
Sieht es bei mir aus wie Ihr versucht, anzeigen gruppierten Daten in einem einzigen Steuerelement aus einem einzigen (verschachtelten) Daten-Quelle, in diesem Fall sollten Sie mithilfe der LongListSelector control aus der Silverlight Toolkit für WP7. WindowsPhoneGeek hat eine guter blog-post darüber, wie es in einer ähnlichen situation wie deine.
Alternativ, würden Sie brauchen, um verschachtelte Elemente steuert. Wenn Sie nicht brauchen, das Konzept der Auswahl, dann setzen Sie einfach die Artikel-Vorlage für die ListBox ein ItemsControl mit ItemsSource="{Binding-Einträge}". Für das ItemsControl, die DataContext wird eine individuelle CategoryItem, so können Sie fügen Sie einen TextBlock, der header, der an die Name-Eigenschaft, falls erforderlich. Dies ist im Grunde, was die LongListSelector ist zu tun, bietet aber mehr Flexibilität.
Wenn Sie brauchen, das Konzept der Auswahl für die Einträge, dann vermute ich, Sie brauchen es nicht an die CategoryItem Ebene, so stellen die Wurzel und ItemsControl und der ItemTemplate eine ListBox. Auf diese Weise Runden Sie müssen vorsichtig sein mit den Blättern, die die ListBox bietet für sich selbst, daher können Sie am Ende mit einer verwirrenden Benutzer-Erfahrung, daher auch mein ursprünglicher Vorschlag, zu versuchen, den LongListSelector.
LongListSelector
könnte meine Bedürfnisse perfekt. Ich werde es versuchen, danke!Annahme 1: UserDataViewModel ist wirklich ein ViewModel
Den Begriff "ViewModel" auf das Ende der Klasse name es impliziert, dass der Zweck dieser Klasse ist die Unterstützung einer bestimmten anzeigen. Sie würde nicht erwarten, dass eine solche Ansicht Modell, um machen es schwierig für die Ansicht, an das es angeschlossen ist, seine Arbeit zu tun.
Ich würde daher vorschlagen, Ihre "ViewModel" ist Durcheinander und braucht Sanierung. Beginnen Sie mit:-
Ihre
CategoryItem
braucht keine Einträge Sammlung Eigentum und IhreUserDataView
gibt eine flache Auflistung allerEntryItem
Objekte. Die Bindung ist einfach.Annahme 2: UserDataViewModel ist nicht wirklich ein ViewModel
Ist es möglich, dass das, was Sie genannt habe, ein view-Modell ist in der Tat nur ein Modell von Daten angeordnet, die in passender Weise Ihrer Speicherung oder Allgemeine Verwendung. Dies wäre der Grund warum es nicht mit den tatsächlichen Anforderungen gerecht wird.
Ich würde vorstellen, eine weitere Annahme, die auf WP7 ist wahrscheinlich wahr sein (wäre wohl an anderer Stelle). Während der Anzeige des view-die Inhalte der Sammlungen werden nicht geändert, noch sind die Namen der items. Daher auch die Beobachtbare Natur dieser Objekte (und möglicherweise nützlich anderswo) sind nicht erforderlich für die Ansicht zu arbeiten.
Wenn diese Annahmen Stimmen, dann einen Wert-Konverter und eine zusätzliche Klasse kann verwendet werden, um die Punkte in akzeptabler Weg:-
Nun würden Sie passen Sie Ihre Xaml:-
Converter
funktioniert perfekt! (Sie vergessen haben, gebenCategoryToEntryItemExConverter
implementiertIValueConverter
, brauchte ein paar Minuten, um herauszufinden, warum ich immer runtime exceptions :-)). Jedoch, wie Sie bereits erwähnt, wenn der Benutzer einen neuen Artikel oder bearbeitet einen vorhandenen, gegeben, dass die Ansicht nicht mehr verbunden mit einemObservableCollection
würde, wie ich die Ansicht aktualisieren? Würde die AktualisierungUserDataViewModel.Data
und dann ruftUpdateLayout()
auf dieListBox
den trick tun? Sorry, ich habe keine des Eintrags Bearbeiten von code in meinem test-Projekt für mich, dies auszuprobieren.UpdateLayout
würde helfen, aber die neu-Zuordnung derUserDataViewModel
zu denDataContext
von der Seite könnte genug sein.Deine Frage nicht wirklich sinnvoll - welches Element in der Liste Einträge wollen Sie die Namen? Das erste Element? Es gibt keinen Namen der gesamten Sammlung nur auf jedes element in dieser Sammlung.
Wenn Sie möchten, dass der erste Artikel, den Sie haben könnte deine TextBox binden Einträge[0].Name - ich denke, das funktioniert für Silverlight auf Windows Phone (ich kann mich nicht erinnern, ob Indexer unterstützt).
Wenn Indexer nicht unterstützt werden, dann würden Sie schreiben müssen, IValueConverter, dass umwandeln können
ObservableCollection<EntityItem>
string und verwenden Sie, dass der Konverter in der Bindung.Entries
Objekt, aber nicht nur der erste, alle von Ihnen. Ich habe auf die Frage, werfen Sie bitte einen Blick.Entries[0].Name
zeigt nur den ersten Eintrag in der jeweiligen Kategorie. Wie kann ich index alle von Ihnen?