C # ListBox из списков списков объектов (и глубже) - PullRequest
1 голос
/ 04 ноября 2010

Рассмотрим книжную полку, у нее есть полки, и на каждой полке есть несколько книг. В свою очередь каждая книга имеет несколько свойств, таких как название и автор и, возможно, ISBN.

namespace mySillyExample
{
  public class BookShelf
  { 
    public Shelf[] myShelves{get; set;}
  }

  public class Shelf
  {
    public Book[] booksOnThisShelf{get; set;}
  }

  public class Book
  {
    public string Title {get; set;};
    public string Author{get; set;};
    public string ISBN {get; set;};
  }
}

Теперь я хотел бы создать список в XAML, используя WPF для вывода списка всех заголовков. Сейчас мое решение выглядит примерно так:

<ListBox Height="154" HorizontalAlignment="Left" 
         ItemsSource="{Binding Path=BookShelf.myShelves}"                  
         Margin="171,475,0,0" VerticalAlignment="Top" Width="333" >
  <ListBox.ItemTemplate>
    <DataTemplate>
      <TextBlock Text="{Binding Path=booksOnThisShelf.[0].Title}" />
    </DataTemplate>
  <ListBox.ItemTemplate>
</ListBox>

И я получаю список с этими данными. В приведенном выше решении я вижу три проблемы.

  1. Кажется, что тег DataTemplate предназначен для изменения типа элемента управления, из которого будет состоять список, а НЕ для предоставления дополнительной области привязки, как она использовалась

  2. Я, кажется, ссылаюсь на 0-й (нулевой / первый) элемент в массиве книг для каждой полки ("booksOnThisShelf. [0]"), это кажется самым злым, поскольку оно не похоже на то, что если я на самом деле получу список всех моих книг (что я делаю)

  3. Кажется, это работает для 2 слоев списков, но как насчет 3, 4 или 42?

Имейте в виду, что я не могу изменить классы напрямую (они сгенерированы в XSD), хотя потенциал вспомогательного класса не обязательно исключен.

Чем больше я думал об этой проблеме, тем больше я убежден, что она должна возникать для большего количества людей, особенно при работе с данными из сложных XML-структур (веб-страниц? Дайте мне все URL-адреса для тегов img и т. Д.)

Итак, вот что я ищу:

  1. Как лучше всего справиться с вышеуказанной проблемой?
    • Самая элегантная / многоразовая модель, которая предпочтительно поддерживается в XAML
  2. Как это можно абстрагировать в n-слоистые списки (объект, содержащий список объектов, содержащий список объектов ... до бесконечности / тошноты)?
    • Используя мой пример, что делать, если у вас есть класс Room с несколькими BookShelves и класс Library с несколькими Rooms и класс City с несколькими библиотеками.

Как всегда заранее спасибо!

ПРИМЕЧАНИЕ: я использовал термин «список», а код показывает массив, мои извинения за путаницу

Ответы [ 3 ]

2 голосов
/ 04 ноября 2010

Я бы посоветовал взглянуть на шаблон MVVM. Вы не привязываетесь к своим моделям, но привязываете к своим моделям представления. Ты ViewModel это то, что поможет вам получить ваш гигантский список. Возможно, вы захотите сделать что-то вроде этого:

//ViewModelBase should be a base class that implements INotifyPropertyChanged
public class MyViewModel : ViewModelBase
{
     public readonly IDataProvider _provider;

     public MyViewModel(IDataProvider provider)
     {
         _provider = provider ?? (some default provider);
     }

     public IList<String> Titles
     {
         get
         {
              var q = from shelves in _provider.GetBookShelves()
                      from books in shelves.booksOnThisShelf
                      select books.Title;

              return q as List<String>;
         }
     }
}

Тогда вам просто нужно установить MyViewModel как ваш DataContext и привязать к заголовкам. Конечно, вам не нужно передавать IDataProvider, вы можете передать список BookShelves, но всегда лучше, чтобы DataProvider получил информацию о вашей модели.

2 голосов
/ 04 ноября 2010

Чтобы показать все заголовки, вы можете создать статический класс / метод для рекурсивного сопоставления всех заголовков и возврата плоского списка. В XAML вы могли бы затем использовать ObjectDataProvider, настроенный для его вызова (статический метод X для типа T), чтобы получить список, который вы можете установить в качестве значения ItemsSource списка.

0 голосов
/ 11 октября 2015

Вы также можете сделать это

<ListBox Height="154" HorizontalAlignment="Left" 
         ItemsSource="{Binding Path=BookShelf.myShelves}"
         DisplayMemberPath="Title"                  
         Margin="171,475,0,0" VerticalAlignment="Top" Width="333" >
</ListBox>
...