【问题标题】:WPF CheckedListBox SelectionMode="Multiple" not updating SelectedIndex on SelectionChanged EventWPF CheckedListBox SelectionMode="Multiple" 未在 SelectionChanged 事件上更新 SelectedIndex
【发布时间】:2015-06-13 15:39:35
【问题描述】:

我正在测试 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>

【问题讨论】:

  • 鉴于 SelectedIndex 是 Multiple 中的第一个,我怀疑这就是它的工作原理。由于您有一个有效的 SelectedItems 集合,请尝试沿着该路径前进。
  • 我可以执行以下操作,但我仍然需要 SelectedIndex 进行相应更改: string test = ((CheckedListItem)listbox1.SelectedItems[listbox1.SelectedItems.Count - 1]).Item.Name ;甚至 CurrentItem 属性也无法正常工作。它卡在列表框字符串 currentItem = ((CheckedListItem)listbox1.Items.CurrentItem).Item.Name; 中的第一个项目上
  • 需要和获取不一样。如果它不开火,它就不会开火。
  • 我不确定你在这里得到了什么。我需要帮助才能使用“Multiple”SelectionMode 更改 SelectedIndex。
  • 如果 SelectedIndex 没有随着 Multiple SelectionMode 发生变化,那么您可能无能为力。这就是控制的工作方式。跳出框框寻找其他到达那里的方法。

标签: c# wpf checkedlistbox


【解决方案1】:

SelectionModeMultiple(或Extended)时控件的工作方式是设置SelectedIndex当第一项被选中时(即添加到@987654328 @)。其他项目被添加到 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;
}

它将达到防止递归调用和后续堆栈溢出的相同目的。我只是不知道取消订阅和订阅事件处理程序是否比布尔检查更便宜或更昂贵(我的猜测是 more 但是研究,似乎没有偏好,如these所示threeresults)。

【讨论】:

    猜你喜欢
    • 2011-02-11
    • 1970-01-01
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 2014-05-02
    • 1970-01-01
    • 2013-10-22
    • 1970-01-01
    相关资源
    最近更新 更多