我正在测试 Kelly Elias 关于 Creating a WPF checkListBox 的文章.我需要获取 selectedIndex 和选中的框文本。一切都按需要工作,直到我将列表框的 SelectionMode 更改为我需要实现的“Multiple”。之后,SelectedIndex 和 SelectedItem 都不会使用 SelectionChanged 事件进行更改。这两个属性只显示第一个复选框的信息。但是,所有选中的复选框都会添加到 SelectedItems 集合中。有人可以协助解决这个问题吗?
先谢谢了!!!
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
namespace Jarloo
{
public class Customer : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
NotifyPropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void NotifyPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class CheckedListItem<T> : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private bool isChecked;
private T item;
public CheckedListItem()
{
}
public CheckedListItem(T item, bool isChecked = false)
{
this.item = item;
this.isChecked = isChecked;
}
public T Item
{
get { return item; }
set
{
item = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Item"));
}
}
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("IsChecked"));
}
}
}
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public ObservableCollection<CheckedListItem<Customer>> Customers { get; set; }
public MainWindow()
{
InitializeComponent();
Customers = new ObservableCollection<CheckedListItem<Customer>>();
Customers.Add(new CheckedListItem<Customer>(new Customer() { Name = "Kelly Smith" }));
Customers.Add(new CheckedListItem<Customer>(new Customer() { Name = "Joe Brown" }));
Customers.Add(new CheckedListItem<Customer>(new Customer() { Name = "Herb Dean" }));
Customers.Add(new CheckedListItem<Customer>(new Customer() { Name = "John Paul" }));
DataContext = this;
}
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
int index = listbox1.SelectedIndex;
string testName = ((CheckedListItem<Customer>)listbox1.SelectedValue).Item.Name;
}
}
}
<Window x:Class="Jarloo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525" WindowStartupLocation="CenterScreen">
<Grid>
<ListBox Name="listbox1" ItemsSource="{Binding Customers}" SelectionChanged="ListBox_SelectionChanged"
SelectionMode="Multiple">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox IsChecked="{Binding RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}, Path=IsSelected}"
Content="{Binding Path=Item.Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
最佳答案
当 SelectionMode
为 Multiple
(或 Extended
)时,控件的工作方式是设置 SelectedIndex
仅第一个项目被选中时(即添加到 SelectedItems
)。其他项目将添加到 SelectedItems
列表的末尾,但 SelectedIndex
保持不变。
为了将此行为引入所需的结果,我们将把新添加的项目从 SelectedItems
的末尾取出,并将其(它们)重新插入到前面。但要实现这一点,我们要做的不仅仅是让最新的项目成为 SelectedItems
中的第一项。我们必须清空列表并重新添加每个条目,以便默认行为现在将所需的项目识别为 SelectedValue
并将更新 SelectedIndex
。因此,我们将使用一个临时列表来提供帮助。
此外,我们将添加一个标志来指示我们当前是否正忙于更正 SelectedItems
顺序。这是必需的,因为我们将修改列表并且 ListBox.SelectionChanged
将被递归调用。
private bool busy;
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (!this.busy)
{
this.busy = true;
/*
* If items were added to the end of the list,
* reverse the list appropriately.
* Removed items are self-handling.
*/
if (e.AddedItems.Count > 0)
{
List<CheckedListItem<Customer>> reversed = new List<CheckedListItem<Customer>>();
// Reverse newly added items.
foreach (var item in e.AddedItems)
{
listbox1.SelectedItems.Remove(item);
reversed.Insert(0, (CheckedListItem<Customer>)item);
}
// Maintain previously reversed items' orders.
foreach (var item in listbox1.SelectedItems)
{
reversed.Add((CheckedListItem<Customer>)item);
}
// Clear and reset selections to trigger SelectedIndex change.
listbox1.UnselectAll();
foreach (var item in reversed)
{
listbox1.SelectedItems.Add(item);
}
}
int index = listbox1.SelectedIndex;
string testName = listbox1.SelectedValue == null ? string.Empty : ((CheckedListItem<Customer>)listbox1.SelectedValue).Item.Name;
System.Console.WriteLine("{0} {1}", index, testName);
this.busy = false;
}
}
旁注:除了 busy
标志和条件检查之外,您还可以执行以下操作:
private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
listbox1.SelectionChanged -= this.ListBox_SelectionChanged;
// Same code within the condition...
listbox1.SelectionChanged += this.ListBox_SelectionChanged;
}
它将达到防止递归调用和后续堆栈溢出的相同目的。我只是不知道取消订阅和订阅事件处理程序是否比 bool 检查更便宜或更昂贵(我的猜测是更多但研究,似乎没有偏好,如these所示three results )。
关于c# - WPF CheckedListBox SelectionMode ="Multiple"不在 SelectionChanged 事件上更新 SelectedIndex,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30820484/