【问题标题】:Cross-ListBox Selects in a Nested ListBox WP7 App嵌套列表框 WP7 应用程序中的跨列表框选择
【发布时间】:2011-09-01 00:10:12
【问题描述】:

在 Windows Phone 7 应用程序中嵌套 ListBox 的一个已知“问题”是,对于每个父类别,它们各自的子 ListBox 保留其自己的 SelectedItems 列表。好吧,我有一种情况,这是预期的行为,但我在捕获父列表框和子列表框选定列表时遇到问题。

当前功能: 1.列表项 2.列表项 3. 正在加载父子列表框数据 4. 父列表框项目的多选工作完美 5.子列表框项目的多选工作,但无法访问 6. UI 中可以为多个不同父项多选子 ListBox 项,但滚动大型列表集时选择丢失且无法访问 7. lstCategory 可以直接访问,但是 lstSubCategory 不能直接访问(可能,我就是不知道怎么弄) 8. 我绑定到一个带有一个复杂对象的 ViewModel,该对象将两个 ListBox 表示为两个 List 对象。

预期功能: 我希望能够同时选择 Category(父)和 SubCategory(子)ListBox 项,如下所示; (X) 表示选中:

  • 面包 (X)
    • 面包 (X)
    • 羊角面包
    • Buscuit (X)
    • 甜甜圈
  • 水果
    • 菠萝 (X)
    • 草莓
  • 饮料 (X)
    • 牛奶 (X)
    • 果汁 (X)
    • 苏打水
  • 零食 (X)
    • 筹码
    • 薯条
    • 线索混音

即使这是一个很长的列表,我也想保留这些选择。所以,我想要捕捉和使用的是:

  • 面包(X)
  • 面包 (X)
  • Buscuit (X)
  • 菠萝 (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 具有预期的 UI 功能(大型列表在滚动时删除交叉选择除外)
  • 当类别和子类别都显示在同一屏幕上时,用户体验感觉最好。
  • 考虑像目录搜索引擎这样的 UI 功能。您可能希望以不同的组合选择一般类别和/或子类别,但父项不应要求子项,子项不应要求父项,但子项和父项都可以存在(为了具体)。

【问题讨论】:

    标签: windows-phone-7 listbox nested dependency-properties multi-select


    【解决方案1】:

    您可以在数据模板中使用复选框而不是文本框,然后将复选框的 IsChecked 属性绑定到 Category/Subcategory 类中的 IsSelected 属性:

        <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));
        }
    }
    

    【讨论】:

    • 使用复选框似乎非常痛苦,当然我的问题也是如此。嵌套控件似乎不必要地复杂。像这样的语句证明了这一点: ListBoxItem checkedItem = this.lstCategory.ItemContainerGenerator.ContainerFromItem((sender as CheckBox).DataContext) as ListBoxItem;
    • 它并不需要异常痛苦。为什么你需要列表框项或复选框?如果您实现 INotifyPropertyChanged 并绑定到模型中的项目,则您不应该需要接触或了解有关复选框或列表框项目的任何内容。
    • 我是 Silverlight 的新手,所以我将研究 INotifyPropertyChanged。我的问题是“为什么我根本无法访问 lstSubCategory”?难道使用嵌套的多选 ListBoxes 从来都不是预期的功能吗?其中有多少应该通过 Bindings 处理(我似乎一直在与之抗争)?
    • 如果列表是虚拟化的,那么子类别列表甚至不存在,除非列表项变得可见。 (所以从屏幕底部掉下来的项目根本没有为它们创建任何组件!)这就是 itemcontainergenerator 东西的来源。我确定在某处使用了多选列表框,它只是在 wpf/silverlight 中,首选行为是尽可能多地进行数据绑定,这样您就不必必须依赖于 ux 行为。那么如果设计师想要将嵌套列表框变成扩展器/等,只要他们进行绑定,一切仍然有效。
    • 这解释了很多,并给了我明确的方向。我对嵌套列表的数据绑定没有足够好的把握。谢谢约翰
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-29
    相关资源
    最近更新 更多