考虑这个简单的例子:
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
我将问题确定为ObservableCollection.Move
方法。看来,只要您致Move(i, i)
(所以实际上没有移动任何东西)i
为SelectedItem
,选择就会变成地狱。
我不是在寻找解决方案。明显的解决方法是不对ObservableCollection
进行排序,并使用CollectionViewSource
或调整Sort
方法仅在两个索引实际不同时调用Move
。
我的问题是,为什么这首先发生?在Move
方法的文档中没有任何迹象表明您不能两次传递相同的参数。此外,没有提示为什么这不适用于CollectionChanged
event或CollectionChangedEventArgs
class的文档。这是WPF中的错误吗?
答案 0 :(得分:0)
我认为这是ItemControl's
事件处理实现中的一个错误。看看这里:
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
<div id="main">
<div class="inline-control-group">
<input type="radio" value="7" id="cf4all1" class="cf4all_radio" name="name1" disabled="disabled">
<label class="cf4all1" for="cf4all1">
<div class="cf4all1inner" style="background-color:#ff2962; width:100%;">
</div>
</label>
</div>
<div class="inline-control-group">
<input type="radio" value="9" id="cf4all2" class="cf4all_radio" name="name2">
<label class="cf4all2" for="cf4all2">
<div class="cf4all2inner" style="background-color:#000000; width:100%;"></div></label>
</div>
</div>
循环内部的意外索引操作。我很惊讶它“只”取消选择该项目并没有完全破坏整个系列。