【问题标题】:WPF AlternationIndex wraps around when moving items to top of list将项目移动到列表顶部时 WPF AlternationIndex 环绕
【发布时间】:2015-10-21 20:36:47
【问题描述】:

我正在尝试制作一个带有行号的 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?

【问题讨论】:

    标签: c# wpf listview data-binding


    【解决方案1】:

    我认为这是一个错误。它的行为是不可接受的。不知何故,AltenrationIndex 设置错误,您可以找到有关此的源代码,但坦率地说,这并不容易理解。这背后有一些算法涉及虚拟化机制以及它们实现的模式。这是我认为可能涉及更新到AlternationIndex的源代码,方法SetAlternationIndex。它在一些回调中被调用,例如当 AlternationCount 改变,item 被移除,...

    这里涉及的一些难以理解的概念是ItemBlockoffset 以及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();
    }
    

    【讨论】:

    • 您的第一个建议对我不起作用(行似乎每次都重复),但调用 ICollectionview.Refresh() 的第二个建议似乎可以解决问题。谢谢!
    猜你喜欢
    • 2010-12-12
    • 2018-04-25
    • 1970-01-01
    • 2023-03-10
    • 2023-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多