简体   繁体   English

使用SelectionMode Multiple / Extended在多个嵌套ListBox中获取所有选定项

[英]Get all selected items across multiple nested ListBoxes with SelectionMode Multiple/Extended

I have a List of Lists and display it with nested ListBoxes : 我有一个ListLists和嵌套显示它ListBoxes

MainWindow.xaml.cs MainWindow.xaml.cs

using System.Collections.Generic;

namespace WPF_Sandbox
{
    public partial class MainWindow
    {

        public IEnumerable<IEnumerable<string>> ListOfStringLists { get; set; } = new[] { new[] { "a", "b" }, new[] { "c", "d" } };

        public MainWindow()
        {
            InitializeComponent();

            DoSomethingButton.Click += (sender, e) =>
            {
                // do something with all selected items
            };
        }

    }
}

MainWindow.xaml MainWindow.xaml

<Window x:Class="WPF_Sandbox.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        x:Name="ThisControl">
    <StackPanel>
        <ListBox ItemsSource="{Binding ListOfStringLists, ElementName=ThisControl}">
            <ListBox.ItemTemplate>
                <ItemContainerTemplate>
                    <ListBox ItemsSource="{Binding}" SelectionMode="Multiple">
                        <ListBox.ItemTemplate>
                            <ItemContainerTemplate>
                                <TextBlock Text="{Binding}" />
                            </ItemContainerTemplate>
                        </ListBox.ItemTemplate>
                    </ListBox>
                </ItemContainerTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
        <Button Name="DoSomethingButton" Content="DoSomething" />
    </StackPanel>
</Window>

How can I get all selected items across all ListBoxes ? 如何在所有ListBoxes获取所有选定的项目?

I found a few solutions getting one selected item but could not figure out how to do applie those in my scenario. 我找到了一些 解决方案获得一个选定的项目,但无法弄清楚如何在我的方案中应用那些。
I have an idea on how to do this by wrapping the string arrays but I would prefer not doing this. 我有一个关于如何通过包装string数组来做到这一点的想法,但我宁愿不这样做。

The easiest way would be to iterate through the items in the ListBox es: 最简单的方法是迭代ListBox es中的项:

private void DoSomethingButton_Click(object sender, RoutedEventArgs e)
{
    List<string> selectedStrings = new List<string>();
    foreach (IEnumerable<string> array in outerListBox.Items.OfType<IEnumerable<string>>())
    {
        ListBoxItem lbi = outerListBox.ItemContainerGenerator.ContainerFromItem(array) as ListBoxItem;
        if (lbi != null)
        {
            ListBox innerListBox = GetChildOfType<ListBox>(lbi);
            if (innerListBox != null)
            {
                foreach (string selectedString in innerListBox.SelectedItems.OfType<string>())
                    selectedStrings.Add(selectedString);
            }
        }
    }
}

private static T GetChildOfType<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj == null)
        return null;

    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
    {
        var child = VisualTreeHelper.GetChild(depObj, i);
        var result = (child as T) ?? GetChildOfType<T>(child);
        if (result != null)
            return result;
    }
    return null;
}

Note that the ListBoxItem may be virtualized away if you have a lot of inner IEnumerable<string> . 请注意,如果您有很多内部IEnumerable<string>ListBoxItem可能会被虚拟化。 You will then have to force the generation of the containers or disable UI virtualization: 然后,您必须强制生成容器或禁用UI虚拟化:

WPF ListView virtualization. WPF ListView虚拟化。 How to disable ListView virtualization? 如何禁用ListView虚拟化?

This may affect the performance negatively so if this is an issue you should probably consider binding to an IEnumerable<YourType> and bind the SelectedItems property of the inner ListBox to a property of a YourType using a behaviour. 这可能会对性能产生负面影响,因此如果这是一个问题,您应该考虑绑定到IEnumerable<YourType>并使用行为将内部ListBoxSelectedItems属性绑定到YourType的属性。

Since the SelectedItems property of a ListBox is read-only you can't bind to it directly: https://blog.magnusmontin.net/2014/01/30/wpf-using-behaviours-to-bind-to-readonly-properties-in-mvvm/ . 由于ListBoxSelectedItems属性是只读的,因此无法直接绑定到它: https//blog.magnusmontin.net/2014/01/30/wpf-using-behaviours-to-bind-to-readonly- properties-in-mvvm /

I would just add an event handler to the inner ListBox like so if not doing things the MVVM way: 我只是添加一个事件处理程序到内部ListBox ,如果没有做MVVM方式:

<ListBox ItemsSource="{Binding}" SelectionMode="Multiple" SelectionChanged="ListBox_SelectionChanged">

Then in your code behind implement the ListBox_SelectionChanged like so: 然后在你的代码后面实现ListBox_SelectionChanged如下所示:

public List<string> FlatStringList = new List<string>();
private void ListBox_SelectionChanged(object sender,System.Windows.Controls.SelectionChangedEventArgs e)
{
    FlatStringList.AddRange(e.AddedItems.Cast<string>());
    foreach(string s in e.RemovedItems)
    {
        FlatStringList.Remove(s);
    }            
}

This is assuming you don't mind storing the selected strings in a flat list. 这假设您不介意将所选字符串存储在平面列表中。 Then you could implement your DoSomething button click event handler to do something with the FlatStringList . 然后,您可以实现DoSomething按钮单击事件处理程序以对FlatStringList执行某些FlatStringList Hope that helps. 希望有所帮助。

Why don't you create a wrapper (as you said): 你为什么不创建一个包装器(如你所说):

public class MyString : INotifyPropertyChanged
{
    public MyString(string value) { Value = value; }

    string _value;
    public string Value { get { return _value; } set { _value = value; RaisePropertyChanged("Value"); } }

    bool _isSelected;
    public bool IsSelected { get { return _isSelected; } set { _isSelected = value; RaisePropertyChanged("IsSelected"); } }

    public event PropertyChangedEventHandler PropertyChanged;
    void RaisePropertyChanged(string propname)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
    }
} 

Bind the IsSelected property of the ListBoxItems: 绑定ListBoxItems的IsSelected属性:

<StackPanel>
    <ListBox ItemsSource="{Binding ListOfStringLists, ElementName=ThisControl}">
        <ListBox.ItemTemplate>
            <ItemContainerTemplate>
                <ListBox ItemsSource="{Binding}" SelectionMode="Multiple">
                    <ListBox.ItemTemplate>
                        <ItemContainerTemplate>
                            <TextBlock Text="{Binding Value}" />
                        </ItemContainerTemplate>
                    </ListBox.ItemTemplate>
                    <ListBox.ItemContainerStyle>
                        <Style TargetType="{x:Type ListBoxItem}">
                            <Setter Property="IsSelected" Value="{Binding IsSelected}"/>
                        </Style>
                    </ListBox.ItemContainerStyle>
                </ListBox>
            </ItemContainerTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
    <Button Name="DoSomethingButton" Content="DoSomething"  />
</StackPanel>

and you are already done: 你已经完成了:

    public IEnumerable<IEnumerable<MyString>> ListOfStringLists { get; set; } = new[] { new[] { new MyString("a"), new MyString("b") { IsSelected = true } }, new[] { new MyString("c"), new MyString("d") } };

    public MainWindow()
    {
        this.InitializeComponent(); 

        DoSomethingButton.Click += (sender, e) =>
        {
            foreach (var i in ListOfStringLists)
                foreach (var j in i)
                {
                    if (j.IsSelected)
                    {
                        // ....
                    }
                }
        };
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用SelectionMode =“ Multiple”和BindableSelection扩展绑定嵌套列表框中的选定项目 - Binding selected items in nested ListBox with SelectionMode=“Multiple” and BindableSelection extension 多个列表框的选定索引 - Selected index for multiple listboxes 如何使用SelectionMode = Multiple从GridView中获取选定的控件 - How to get selected controls from GridView with SelectionMode=Multiple 如何使用 SelectionMode=&quot;Extended&quot; 在 MVVM 中设置所选项目? - How to set selected items in MVVM using SelectionMode=“Extended”? 如何在SelectionMode为多个的情况下设置Listpicker项目 - how to set Listpicker items where SelectionMode is multiple 如何将数据绑定并填充/显示从ListBox选定项的DataGrid或UniformGrid(SelectionMode = Multiple) - How to bind data and fill/display to DataGrid or UniformGrid from ListBox selected items (SelectionMode=Multiple) 如何仅使用一个 for 循环来反转多个列表框中的选定项目? - How can I invert the selected items in multiple listboxes using only one for loop? C#如何在多个列表框中显示项目? - C# How to display items in multiple listboxes? ListPicker“ SelectionMode = Multiple”出现问题 - Issue with ListPicker “SelectionMode = Multiple” 遍历所有ListBox的选定项目,然后转移到一个ListBox - Loop through all ListBoxes for selected items and transfer over to one ListBox
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM