为什么在对ItemsSource排序时ComboBox会丢失其SelectedItem? [英] Why is the ComboBox losing its SelectedItem when sorting the ItemsSource?

查看:134
本文介绍了为什么在对ItemsSource排序时ComboBox会丢失其SelectedItem?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下简单示例:

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>
        <ComboBox ItemsSource="{Binding Collection, ElementName=ThisControl}" SelectedItem="a" />
        <Button x:Name="SortButton">Sort</Button>
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace WPF_Sandbox
{
    public partial class MainWindow
    {
        public ObservableCollection<string> Collection { get; } = new ObservableCollection<string>(new [] { "b", "a", "c" });

        public MainWindow()
        {
            InitializeComponent();

            SortButton.Click += (s, e) => Sort(Collection);
        }

        public static void Sort<T>(ObservableCollection<T> collection)
        {
            var sortableList = new List<T>(collection);
            sortableList.Sort();

            for (var i = 0; i < sortableList.Count; i++)
                collection.Move(collection.IndexOf(sortableList[i]), i);
        }
    }
}

启动程序时,选择了a.按下Sort时,选择不会更改,但列表会被排序(仍然按预期).
如果您a)再次按Sort或b)在排序之前选择bc,则ComboBox将丢失选择,而SelectedItem变为null.

When starting the program, a is selected. On pressing Sort the selection doesn't change but the list gets sorted (still as expected).
If you a) press Sort again or b) select b or c before sorting, the ComboBox loses its selection and SelectedItem becomes null.

我将问题归结为 ObservableCollection.Move 方法.看来,每当您以iSelectedItem的方式呼叫Move(i, i)(因此您实际上不会移动任何东西)时,选择都会下地狱.

I pinpointed the issue down to the ObservableCollection.Move method. It appears that whenever you call Move(i, i) (so you do not actually move anything) with i being the SelectedItem, the selection goes to hell.

我不是在寻找解决方案.明显的解决方法是完全不对ObservableCollection进行排序,而仅使用CollectionViewSource或将Sort方法调整为仅在两个索引实际上不同时才调用Move.

I'm not looking for a solution. Obvious workaround would be to not sort the ObservableCollection at all and use a CollectionViewSource or adjusting the Sort method to only call Move when the two indices actually differ.

我的问题是,为什么这首先发生? Move 方法,您不能两次传递相同的参数.此外,在

The question I have is, why is this happening in the first place? There is no indication in documentation for the Move method that you must not pass the same parameter twice. Also there is no hint why this would not work in the documentation for the CollectionChanged event or the CollectionChangedEventArgs class. Is this a bug in WPF?

推荐答案

我相信这是ItemControl's事件处理的实现中的错误.在这里看看:

I believe this to be a bug in the implementation of the ItemControl's event handling. Take a look here:

case NotifyCollectionChangedAction.Move:
    // items between New and Old have moved.  The direction and
    // exact endpoints depends on whether New comes before Old.
    int left, right, delta;
    if (e.OldStartingIndex < e.NewStartingIndex)
    {
        left = e.OldStartingIndex + 1;
        right = e.NewStartingIndex;
        delta = -1;
    }
    else
    {
        left = e.NewStartingIndex;
        right = e.OldStartingIndex - 1;
        delta = 1;
    }

    foreach (ItemInfo info in list)
    {
        int index = info.Index;
        if (index == e.OldStartingIndex)
        {
             info.Index = e.NewStartingIndex;
        }
        else if (left <= index && index <= right)
        {
             info.Index = index + delta;
        }
    }
break;

来源

if语句似乎不希望e.OldStartingIndexe.NewStartingIndex具有相同的值,从而导致delta1,这随后会导致foreach循环内的某些意外索引操作.我很惊讶它仅"取消选择了该项目,而没有完全破坏整个收藏集.

The if statement does not seem to expect e.OldStartingIndex and e.NewStartingIndex to be of the same value which results in delta being 1 which then causes some unintended index manipulation inside of the foreach loop. I'm surprised it "only" deselects the item and not completely ruins the whole collection.

这篇关于为什么在对ItemsSource排序时ComboBox会丢失其SelectedItem?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆