我尝试使用行号创建一个GridView,并且为用户提供上/下按钮以更改行的顺序。许多帖子建议使用AlternationIndex(例如here)并且几乎完美地工作,并且当用户按下向上/向下按钮以更改行的顺序时它会处理。但是,当您将项目移动到第一个位置时,AlternationIndex会失败 - 此时,它应该显示0,但它会转换为AlternationCount中的最后一个值。
示例:
<ListView AlternationCount="1000" Name="_stuff" Grid.Row="0">
<ListView.View>
<GridView>
<GridViewColumn
Header="Alit" Width="30"
DisplayMemberBinding="{Binding (ItemsControl.AlternationIndex),
RelativeSource={RelativeSource AncestorType=ListViewItem}}" />
<GridViewColumn Header="ColumnName" DisplayMemberBinding="{Binding}" Width="240"/>
</GridView>
</ListView.View>
</ListView>
然后我的代码隐藏是:
ObservableCollection<string> data = new ObservableCollection<string>() { "First", "Second", "Third", "Forth", "Last" };
public MainWindow()
{
InitializeComponent();
_stuff.ItemsSource = data;
}
private void UpDownButton_Click(object sender, RoutedEventArgs e)
{
//User wants to change the order -- remove the item from the observable
//collection and reinsert it at the new position.
data.Remove("Last"); //First remove, then re-insert.
//If you move the last item to *middle* of list, it works fine and the index
//is correct. (All other items are pushed down by 1, like you'd expect.)
//But move to the *top* of the list and the new index is 999?
//THIS WOULD WORK FINE AND ALL INDEXES ARE CORRECT
// data.Insert(3, "Last"); //Insert to middle of list
//But this gives an index of 999???? Seems to be wrapping
//around to the last AlternationCount. But why?
data.Insert(0, "Last"); //insert to top of list
}
任何想法如何让顶部的新项目的alternationIndex为0而不是999?
答案 0 :(得分:1)
我认为这是一个错误。它表现得像那样是不可接受的。不知何故,AltenrationIndex
设置错误,您可以找到关于此的源代码,但坦率地说,它并不是很容易理解。这背后有一些算法涉及虚拟化机制以及它们实现的模式。以下是我认为可能涉及更新AlternationIndex
方法SetAlternationIndex的源代码。它在一些回调中被调用,例如当AlternationCount被更改时,项目被删除,......
此处涉及的一些难以理解的概念包括ItemBlock
和offset
以及GeneratorDirection
。这就是为什么我很难理解那里的代码。
我发布这个答案是因为我找到了一个简单的解决方案,虽然我不确定它是否存在性能问题,但我确信它应该可以接受。
如果重新生成项容器,则AlternationIndex
应该再次排序。因为在虚拟化模式下,项容器的数量只等于可见元素的数量,所以我认为这不会导致性能问题。 ItemContainerGenerator
实现了具有名为IItemContainerGenerator
的方法的接口RemoveAll
。通过使用此方法,将删除所有已实现(生成)的项容器,并且将再次自动生成它们,从而导致AlternationIndex
按正确顺序设置。
另外,正如您所说,只有在第一个索引处插入项目时才会出现问题。所以我们只需要在特定情况下使用这个技巧:
private void UpDownButton_Click(object sender, RoutedEventArgs e)
{
//before changing any item at index 0 such as by inserting
//some new one or even use the method Move(... , 0),
//We need to clear all the realized item containers
var cg = _stuff.ItemContainerGenerator as IItemContainerGenerator;
cg.RemoveAll();
//now just proceed the code
//we can in fact use this instead data.Move(data.Count - 1, 0);
data.Remove("Last");
data.Insert(0, "Last");
}
这是使用ICollectionView.Refresh()
方法的另一个非常好的解决方案。您只需要刷新它(但当然只应在出现问题时应用):
private void UpDownButton_Click(object sender, RoutedEventArgs e)
{
//we can in fact use this instead data.Move(data.Count - 1, 0);
data.Remove("Last");
data.Insert(0, "Last");
CollectionViewSource.GetDefaultView(data).Refresh();
}