将复选框列表绑定到已检查值列表的最简单方法是什么

时间:2022-04-11 11:49:22

I have a list of AvailableItems that I want to display as a list of checkboxes, so that users can pick which items to generate, which are then stored in another list called ItemsToGenerate (my lists are actually just lists of strings).

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

Showing all available items with corresponding checkboxes is easy:

显示包含相应复选框的所有可用项目很简单:

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

But now I need to bind each Checkbox.IsChecked property, to the fact that the item is in the ItemsToGenerate list. I thought of making a ListContainmentToBoolConverter like this:

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

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

But that doesn't work because I'm missing a ConverterParameter to pass the value of each item, but I can't do that, because ConverterParameter does not support binding.

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

Any ideas?

有任何想法吗?

2 个解决方案

#1


12  

I've found a solution to my problem.

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

I've changed my ItemsControl to a ListBox, and added a binding between the SelectedItems with my ItemsToGenerate collection using the technique described here. It basically allows me to synchronize any custom collection to ListBox.SelectedItems using a simple attached property.

我已将ItemsControl更改为ListBox,并使用此处描述的技术在SelectedItems与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>

I'm still able to display this as I initially wanted (a list of checkboxes), by adding a data template to change each ListBoxItem to a checkbox and binding each Checkbox.IsChecked to ListBoxItem.IsSelected.

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

I had this pattern in so many places in my application that this is the ideal solution for me, because now I just need to specify one attached property, and the rest is all handled by the data bindings, and I don't need any additional code.

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

#2


7  

I honestly would create a list of objects containing both the string and a boolean indicating if it is checked.

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

With a little Linq you can generate your list of objects and bind it to itemSource instead of binding the list of strings.

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

It will be simpler in the end, especially if you actually need to update something if the user is allowed to check/uncheck the checkboxes.

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

== update ==

==更新==

in answer to the comment, my take on this because I'm not sure I understand what the actual problem would be: provided we have the full list (AvailableItems) and the list of selected items (ItemsToGenerate):

在回答评论时,我对此有所了解,因为我不确定我理解实际问题是什么:只要我们有完整列表(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();

You can then bind your list like so, by exposing _Items as a property named Items:

然后,您可以通过将_Items公开为名为Items的属性来绑定您的列表。

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

You can at a later time select from _Items where IsSelected is true to get the selected items if you need to.

您可以稍后从_Items中选择IsSelected为true,以便在需要时获取所选项目。

Also, if ItemsToGenerate can get big, you should create a HashSet of the values and use it in the query, that should make it faster if need be.

此外,如果ItemsToGenerate可以变大,您应该创建值的HashSet并在查询中使用它,如果需要,它应该更快。

#1


12  

I've found a solution to my problem.

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

I've changed my ItemsControl to a ListBox, and added a binding between the SelectedItems with my ItemsToGenerate collection using the technique described here. It basically allows me to synchronize any custom collection to ListBox.SelectedItems using a simple attached property.

我已将ItemsControl更改为ListBox,并使用此处描述的技术在SelectedItems与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>

I'm still able to display this as I initially wanted (a list of checkboxes), by adding a data template to change each ListBoxItem to a checkbox and binding each Checkbox.IsChecked to ListBoxItem.IsSelected.

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

I had this pattern in so many places in my application that this is the ideal solution for me, because now I just need to specify one attached property, and the rest is all handled by the data bindings, and I don't need any additional code.

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

#2


7  

I honestly would create a list of objects containing both the string and a boolean indicating if it is checked.

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

With a little Linq you can generate your list of objects and bind it to itemSource instead of binding the list of strings.

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

It will be simpler in the end, especially if you actually need to update something if the user is allowed to check/uncheck the checkboxes.

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

== update ==

==更新==

in answer to the comment, my take on this because I'm not sure I understand what the actual problem would be: provided we have the full list (AvailableItems) and the list of selected items (ItemsToGenerate):

在回答评论时,我对此有所了解,因为我不确定我理解实际问题是什么:只要我们有完整列表(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();

You can then bind your list like so, by exposing _Items as a property named Items:

然后,您可以通过将_Items公开为名为Items的属性来绑定您的列表。

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

You can at a later time select from _Items where IsSelected is true to get the selected items if you need to.

您可以稍后从_Items中选择IsSelected为true,以便在需要时获取所选项目。

Also, if ItemsToGenerate can get big, you should create a HashSet of the values and use it in the query, that should make it faster if need be.

此外,如果ItemsToGenerate可以变大,您应该创建值的HashSet并在查询中使用它,如果需要,它应该更快。