Перекрестный список выбирается во вложенном приложении ListBox WP7 - PullRequest
0 голосов
/ 24 мая 2011

Известная «проблема» с вложенностью ListBoxes в приложении Windows Phone 7 заключается в том, что для каждой родительской категории их соответствующий дочерний ListBox сохраняет свой собственный список SelectedItems. Ну, у меня есть ситуация, когда это ожидаемое поведение, но у меня возникают проблемы с захватом списков, выбранных как для родительского, так и для дочернего списка.

Текущая функциональность: 1. Элемент списка 2. Элемент списка 3. Загрузка данных родительского и дочернего ListBox работает 4. Мульти-выбор элементов Родительского ListBox работает идеально 5. Множественный выбор дочерних элементов ListBox работает, но не доступен 6. В пользовательском интерфейсе работает множественный выбор дочерних элементов ListBox для нескольких разных родителей, но выбор теряется при прокрутке больших наборов списков и недоступен 7. lstCategory доступна напрямую, но lstSubCategory недоступна напрямую (возможно, я просто не знаю как) 8. Я привязан к ViewModel с одним сложным объектом, который представляет два ListBox как два объекта List.

Ожидаемая функциональность: Я хотел бы иметь возможность выбирать элементы ListBox как Category (родительский), так и SubCategory (дочерний) следующим образом; (X) Обозначает выбранное:

  • Хлеб (X)
    • Буханка (X)
    • Круассан
    • Buscuit (X)
    • Donut
  • Фрукты
    • Pinaple (X)
    • Клубника
  • напитки (X)
    • Вода
    • Молоко (X)
    • Сок (X)
    • Сода
  • Закуски (X)
    • Чипсы
    • Fries
    • Trail Mix

Я хотел бы сохранить выбор, даже если это был длинный список. Итак, я хочу захватить и работать с ним:

  • Хлеб (X)
  • Буханка (X)
  • Buscuit (X)
  • Pinaple (X)
  • Напитки (X)
  • Молоко (X)
  • Сок (X)
  • Закуски (X)

Поскольку у меня есть CategoryID в каждом из объектов, я могу убрать информацию о иерархии при захвате.

Для краткости, вот суть кода:

        <ListBox 
            x:Name="lstCategory"
            SelectionMode="Multiple" 
            ItemsSource="{Binding Categories}" 
            FontSize="32" 
            Margin="0,0,0,67">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel>
                        <StackPanel Orientation="Vertical">
                            <TextBlock Text="{Binding CategoryName}"
                                        FontSize="36"
                                        TextWrapping="Wrap"
                                        Margin="20,0,0,0"
                                        VerticalAlignment="Top"/>
                            <StackPanel  Orientation="Vertical" Margin="60,0,0,0">
                                <ListBox
                                    x:Name="lstSubCategory"
                                    SelectionMode="Multiple" 
                                    ItemsSource="{Binding SubCategories}">
                                    <ListBox.ItemTemplate>
                                        <DataTemplate>
                                            <TextBlock Text="{Binding SubCategoryName}"
                                                       FontSize="28"
                                                       TextWrapping="Wrap"
                                                       VerticalAlignment="Top"/>
                                        </DataTemplate>
                                    </ListBox.ItemTemplate>
                                </ListBox>
                            </StackPanel>
                        </StackPanel>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

И ViewModel:

    public List<Category> Categories { get; set; }

    public PostCategorySelectVM()
    {
        Categories = new List<Category>()
        {
            new Category() 
            { 
                CategoryID = 0, 
                CategoryName = "Bread",
                SubCategories = new List<SubCategory>()
                {
                    new SubCategory() {
                        CategoryID = 001,
                        SubCategoryName = "Loaf"
                    },
                    new SubCategory() {
                        CategoryID = 002,
                        SubCategoryName = "Croissant"
                    }
                    // ...
                }
                // ...
            }
            // ...
        }
    }

Категория Класс:

public class Category
{
    public int CategoryID { get; set; }
    public string CategoryName { get; set; }
    public List<SubCategory> SubCategories { get; set; }
}

Класс подкатегории:

public class SubCategory
{
    public int CategoryID { get; set; }
    public string SubCategoryName { get; set; }
}

Событие нажатия кнопки «Сохранить»:

    private void btnSave_Click(object sender, RoutedEventArgs e)
    {
        foreach (Category item in lstCategory.SelectedItems)
        {
            catList.Add(item);
        }

        foreach (Category cat in catList)
        {
            scatList = cat.SubCategories;
            foreach (SubCategory scat in scatList)
            {
                // How do I select the "Selected" SubCategories?
                // How do I select the lstSubCategory control?
            }
        }
    }

Заключительные замечания:

  • Единственное, что у меня есть, связано со свойствами зависимости, но единственные примеры, которые я видел, требуют FrameworkPresentation.dll, который недоступен в WP7.
  • Вложенный ListBox обладает ожидаемой функциональностью пользовательского интерфейса (за исключением больших списков, удаляющих перекрестные выделения при прокрутке)
  • Пользовательский опыт чувствует себя лучше, когда и Категория, и Подкатегория отображаются на одном экране.
  • Рассматривайте функциональность пользовательского интерфейса как механизм поиска по каталогам. Возможно, вы захотите выбрать общую категорию и / или подкатегории в различных комбинациях, но родитель не должен требовать ребенка, а ребенок не должен требовать родителя, хотя могут существовать как ребенок, так и родитель (для конкретности).

1 Ответ

1 голос
/ 25 мая 2011

Вы можете использовать флажки вместо текстовых в ваших шаблонах данных, а затем связать свойство IsChecked флажков со свойством IsSelected в ваших классах Category / Subcategory:

    <ListBox x:Name="lstCategory"
        ItemsSource="{Binding Categories}" 
        FontSize="32" 
        Margin="0,0,0,67">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Vertical">
                    <CheckBox Content="{Binding CategoryName}"
                                FontSize="36"
                                IsChecked="{Binding IsSelected,Mode=TwoWay}"
                                Margin="20,0,0,0"
                                VerticalAlignment="Top"/>
                    <ListBox ItemsSource="{Binding SubCategories}" Margin="60,0,0,0">
                        <ListBox.ItemTemplate>
                            <DataTemplate>
                                <CheckBox Content="{Binding SubCategoryName}"
                                            FontSize="28"
                                            IsChecked="{Binding IsSelected,Mode=TwoWay}"
                                            VerticalAlignment="Top"/>
                            </DataTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Вы также должны иметь классы категорий / подкатегорий, реализующие INotifyPropertyChanged для корректного запуска уведомлений, когда установлен IsSelected.

при условии, что ваше сохранение будет выглядеть примерно так (это не точно!)

private void btnSave_Click(object sender, RoutedEventArgs e)
{
    catList.Clear();
    catList.AddRange( lstCategory.Items.OfType<Category>().Where(x=>x.IsSelected));

    scatList.Clear();
    foreach (Category cat in catList)
    {
        scatList.AddRange(cat.SubCategories.Where(x=>x.IsSelected));
    }
}
...