我有List
Lists
并使用嵌套ListBoxes
显示它:
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
<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>
如何在所有ListBoxes
中获取所有选定的项目?
我发现few solutions获得了一个选定的项目,但无法弄清楚如何在我的方案中应用这些项目。
我知道如何通过包装string
数组来实现这一点,但我不想这样做。
答案 0 :(得分:1)
最简单的方法是遍历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;
}
请注意,如果你有很多内部ListBoxItem
,IEnumerable<string>
可能会被虚拟化。然后,您必须强制生成容器或禁用UI虚拟化:
这可能会对性能产生负面影响,因此如果这是一个问题,您应该考虑绑定到IEnumerable<YourType>
并将内部SelectedItems
的{{1}}属性绑定到ListBox
的属性{1}}使用行为。
由于YourType
的{{1}}属性是只读的,因此您无法直接绑定到IO.foreach
。
答案 1 :(得分:1)
我只是向内部ListBox
添加一个事件处理程序,如果不是以MVVM的方式做事:
<ListBox ItemsSource="{Binding}" SelectionMode="Multiple" SelectionChanged="ListBox_SelectionChanged">
然后在你的代码背后实现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);
}
}
这假设您不介意将所选字符串存储在平面列表中。然后,您可以实施DoSomething
按钮点击事件处理程序,以便对FlatStringList
执行某些操作。
希望有所帮助。
答案 2 :(得分:1)
为什么不创建一个包装器(如你所说):
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));
}
}
绑定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>
你已经完成了:
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)
{
// ....
}
}
};
}