WP7 - Binding ListBox to Nested ObservableCollection

I have ObservableCollectionobjects as follows:

public class UserDataViewModel
{
  private ObservableCollection<CategoryItem> _data = 
                                       new ObservableCollection<CategoryItem>();

  public ObservableCollection<CategoryItem> Data
  {
    get { return _data; }
    private set { }
  }
  // Other methods to set Data
}

A class is CategoryItemdefined as:

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
}

A class is EntryItemdefined as:

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
}

I am trying to relate this to ListBox. Each ListBoxItemconsists of 2 TextBlocks. I want the first to TextBlockdisplay the property EntryItem.Nameand the second to display the property CategoryItem.Name. Here is what I tried in XAML (without success):

<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 the code for this page, I install:

DataContext = App.ViewModel; // ViewModel is of type UserDataViewModel

I keep getting a binding error:

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')..

NestedCollectionis the name of this project, and all the classes listed above are in the namespace NestedCollection.ViewModels.

Only the contents of the second are displayed TextBlock. How to fix it?

Thanks for your help, it made me go for hours!

EDIT:

, Data 2 : " " " " ( Name CategoryItem ). , CategoryItem EntryItem "Visa", "Mastercard" "American Express", CategoryItem EntryItem "GMail" "Hotmail", , ListBox :

Visa
Credit Cards

Mastercard
Credit Cards

American Express
Credit Cards

GMail
Email Accounts

Hotmail
Email Accounts

, Entries Data Name, . Entries XAML?

+3
4

ObservableCollection<T> TextBox. .

ObservableCollection<EntryItem> Name. EntryItem .

ItemsControl Converter EntryItem -.

:

:

<ListBox x:Name="MyListBox"
            Margin="0,0,-12,0"
            ItemsSource="{Binding Data}">
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Grid Name="RootGrid">
                <ItemsControl ItemsSource="{Binding Entries}">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Margin="0,0,0,17">
                                <!--This should display EntryItem.Name-->
                                <TextBlock Text="{Binding Name}"
                                            TextWrapping="Wrap"
                                            Margin="12,0,0,0"
                                            Style="{StaticResource PhoneTextExtraLargeStyle}" />
                                <!--This should display CategoryItem.Name-->
                                <TextBlock Text="{Binding ElementName=RootGrid, Path=DataContext.Name}"
                                            TextWrapping="Wrap"
                                            Margin="12,-6,0,0"
                                            Style="{StaticResource PhoneTextSubtleStyle}" />
                            </StackPanel>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
            </Grid>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

- EDIT -

, Silverlight 3.

http://forums.silverlight.net/forums/p/108804/280986.aspx

, CategoryItem EntryItem Parent, - .

public class EntryItem : INotifyPropertyChanged
{
    public CategoryItem Parent { get; set; }
    ....
}

, , DataTemplate UserControl, .

+3

, () , LongListSelector Silverlight Toolkit WP7. WindowsPhoneGeek , .

, . , ListBox ItemsControl ItemsSource = "{Binding Entries}". ItemsControl DataContext CategoryItem, TextBlock, Name. , LongListSelector, .

, , CategoryItem, root ItemsControl ItemTemplate ListBox. , , ListBox , , LongListSelector.

+2

1: UserDataViewModel - ViewModel

"ViewModel" , . , , , .

, "ViewModel" . : -

public class EntryItem
{
    public string Name {get; set;}
    public CategoryItem Category {get; set;}
}

CategoryItem collection, UserDataView EntryItem. .

   <TextBlock Text="{Binding Name}"
                   TextWrapping="Wrap"
                   Margin="12,0,0,0"
                   Style="{StaticResource PhoneTextExtraLargeStyle}" />
   <TextBlock Text="{Binding Category.Name}"
                   TextWrapping="Wrap"
                   Margin="12,-6,0,0"
                   Style="{StaticResource PhoneTextSubtleStyle}" />   

2: UserDataViewModel ViewModel

, , , , . , .

, WP7, , (, ). . , ( ) .

, : -

public class EntryHolder
{
    public EntryItem Entry {get; set;}
    public CategoryItem Category {get; set; }
}

public class CategoryToEntryItemExConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
         UserDataViewModel model = value as UserDataViewModel;
         if (model != null)
         {
              return model.Data.SelectMany(c => c.Entries
                 .Select(e => new EntryHolder() { Category = c, Entry = e})
              );
         }
         else
         {
             return null;
         }
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

Xaml: -

<Grid x:Name="LayoutRoot">
    <Grid.Resources>
   <local:CategoryToEntryItemExConverter x:Key="ItemsConv" />
</Grid.Resources>
</Grid>

...

<ListBox x:Name="MyListBox"
         Margin="0,0,-12,0"
         ItemsSource="{Binding Converter={StaticResource ItemsConv}}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <StackPanel Margin="0,0,0,17">
        <!--This should display EntryItem.Name-->
        <TextBlock Text="{Binding Entry.Name}"
                   TextWrapping="Wrap"
                   Margin="12,0,0,0"
                   Style="{StaticResource PhoneTextExtraLargeStyle}" />

        <!--This should display CategoryItem.Name-->
        <TextBlock Text="{Binding Category.Name}"
                   TextWrapping="Wrap"
                   Margin="12,-6,0,0"
                   Style="{StaticResource PhoneTextSubtleStyle}" />
      </StackPanel>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>  
+2

Your question does not make sense - what element in the list of records do you want to name? First element? The name of the entire collection is missing, only for each item in this collection.

If you want the first element you can bind the TextBox to the [0] .Name entries - I think this works for Silverlight on Windows Phone (I can't remember if indexes are supported).

If indexes are not supported, you will need to write an IValueConverter that can convert from ObservableCollection<EntityItem>to string and use this as a converter in a binding.

+1
source

Source: https://habr.com/ru/post/1784017/


All Articles