【问题标题】:What's the simplest way to bind a list of checkboxes to a list of checked values将复选框列表绑定到选中值列表的最简单方法是什么
【发布时间】:2009-04-23 18:36:43
【问题描述】:

我有一个 AvailableItems 列表,我想将其显示为复选框列表,以便用户可以选择要生成的项目,然后将其存储在另一个名为 ItemsToGenerate 的列表中(我的列表实际上只是列表字符串)。

用相应的复选框显示所有可用的项目很容易:

<ItemsControl ItemsSource="{Binding Path=AvailableItems}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <CheckBox Content="{Binding}" />
        </DataTemplate>
    </ItemsControl.ItemTemplate>    
</ItemsControl>

但现在我需要将每个 Checkbox.IsChecked 属性绑定到该项目位于 ItemsToGenerate 列表中的事实。我想过像这样制作ListContainmentToBoolConverter

IsChecked="{Binding Path=ItemsToGenerate, 
            Converter={StaticResource ListContainmentToBoolConverter}}"

但这不起作用,因为我缺少ConverterParameter 来传递每个项目的值,但我不能这样做,因为ConverterParameter 不支持绑定。

有什么想法吗?

【问题讨论】:

    标签: wpf binding


    【解决方案1】:

    我找到了解决问题的方法。

    我已将我的ItemsControl 更改为ListBox,并使用here 描述的技术在我的ItemsToGenerate 集合之间添加了一个绑定。它基本上允许我使用简单的附加属性将任何自定义集合同步到ListBox.SelectedItems

    <ListBox ItemsSource="{Binding AvailableItems}"
             Behaviors:MultiSelectorBehaviours.SynchronizedSelectedItems=
                 "{Binding ItemsToGenerate}"
             SelectionMode="Multiple"
             Background="{x:Null}">  
        <ItemsControl.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel />                    
            </ItemsPanelTemplate>
        </ItemsControl.ItemsPanel>
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <CheckBox Content="{Binding}"
                          Margin="3"
                          IsChecked="{Binding RelativeSource=
                               {RelativeSource Mode=FindAncestor,
                                AncestorType={x:Type ListBoxItem}},
                               Path=IsSelected}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ListBox>
    

    通过添加一个数据模板将每个ListBoxItem 更改为一个复选框并将每个Checkbox.IsChecked 绑定到ListBoxItem.IsSelected,我仍然能够按照我最初想要的方式显示它(复选框列表)。

    我的应用程序中很多地方都有这种模式,这对我来说是理想的解决方案,因为现在我只需要指定一个附加属性,其余的都由数据绑定处理,而我不需要需要任何额外的代码。

    【讨论】:

    • 我想看看你的附加属性的实现。不幸的是,这仅在您重复使用 ListBox 中的选择时才有效,但是如果您在模板中使用带有复选框的 ItemsControl 怎么办?
    • 我试过这个,最终结果看起来有点时髦 (i.imgur.com/ZRyrjfe.png)。我个人会坚持使用普通的 ListBox。
    【解决方案2】:

    老实说,我会创建一个对象列表,其中包含字符串和一个布尔值,指示是否已检查。

    使用一点 Linq,您可以生成对象列表并将其绑定到 itemSource,而不是绑定字符串列表。

    最后会更简单,特别是如果您确实需要更新某些内容,如果允许用户选中/取消选中复选框。

    == 更新 ==

    作为对评论的回答,我对此的看法是因为我不确定我是否理解实际的问题:只要我们有完整的列表 (AvailableItems) 和选定项目的列表 (ItemsToGenerate):

    public class ItemEntry
    {
      public string Name { get; set; }
      public bool IsSelected {get; set; }
    }
    

    ...

    _Items = from item in AvailableItems
                select new ItemEntry() { 
                        Name = item, 
                        IsSelected = ItemsToGenerate.contains(item)
                      }).ToList();
    

    然后,您可以像这样绑定您的列表,方法是将 _Items 公开为名为 Items 的属性:

    <ItemsControl ItemsSource="{Binding Path=Items}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <CheckBox Content="{Binding Name}" IsChecked="{Binding IsSelected}" />
            </DataTemplate>
        </ItemsControl.ItemTemplate>    
    </ItemsControl>
    

    如果需要,您可以稍后从 IsSelected 为 true 的 _Items 中选择以获取所选项目。

    另外,如果 ItemsToGenerate 可以变大,你应该创建一个值的 HashSet 并在查询中使用它,如果需要的话应该会更快。

    【讨论】:

    • 我不想这样做的原因是因为我的数据被保存到 xml 并且有时是手动编辑的。因此,如果有 300 个项目可用并且他们只想生成 2 个项目,我希望他们只写 Item1Item2.
    • 我想到了另一种方法来解决这个问题:使用项目模板将 checkbox.IsChecked 绑定到 ListItem.IsSelected 的 ListBox。那么这只是将 ItemsSource 绑定到 AvailableItems 并将 SelectedItems 绑定到 ItemsToGenerate 的问题。
    • 您使用 linq 的方法似乎可以满足我的要求,所以我会尝试一下。但是如果我理解的话,我将不得不使用 Linq 手动更新 ItemsToGenerate(它不是绑定)。我希望它尽可能简单的原因是我有很多地方可以使用这种模式:选择要编译的目标、要使用的语言、要生成的世界、要运行的任务等. 我想最小化数据格式,但在 UI 中显示所有可用选项。
    • 如果你想实现你最初的想法,你可以使用一个多值转换器的多重绑定。它将不接受任何参数并绑定到项目和 ItemsToGenerate 集合。
    • 我尝试制作一个多值转换器,将第一个值绑定到项目,将第二个值绑定到列表 ItemsToGenerate,如果项目不在列表中,我会正确返回 true 或 false。但是我怎样才能转换回来? convert back 方法只接收一个布尔值。我缺少列表和项目值,因此我可以将项目添加/删除到列表中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-14
    • 1970-01-01
    • 1970-01-01
    • 2015-02-07
    相关资源
    最近更新 更多