为什么在对ItemsSource排序时ComboBox会丢失其SelectedItem? [英] Why is the ComboBox losing its SelectedItem when sorting the ItemsSource?
问题描述
考虑以下简单示例:
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)在排序之前选择b
或c
,则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
方法.看来,每当您以i
为SelectedItem
的方式呼叫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
方法,您不能两次传递相同的参数.此外,在 CollectionChangedEventArgs
类.这是WPF中的错误吗?
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.OldStartingIndex
和e.NewStartingIndex
具有相同的值,从而导致delta
为1
,这随后会导致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屋!