【问题标题】:wpf datagrid drag row on Icollectionview which bind to collection绑定到集合的 Icollectionview 上的 wpf datagrid 拖动行
【发布时间】:2014-07-22 05:52:25
【问题描述】:

我有一个这样的数据网格

        _productsPosition = new ObservableCollectionEx<NotifiedPositionInfo>();
        _itemSourceList = new CollectionViewSource() { Source = _productsPosition };
        _itemSourceList.Filter += new FilterEventHandler(FilteringProduct);
        PositionsGrid.ItemsSource = _itemSourceList.View;

当我尝试在这个数据网格上拖动行时,我可以获得集合视图上的行索引。但是这个索引并不能帮我获取集合_productsPosition中的相同元素,因为collectionView被过滤器修改了。

因此,我有一个问题,我怎样才能只在 collectionview 上移动元素,而不是 _productsPosition。像这样抛出异常的东西:

        NotifiedPositionInfo prev_position = PositionsGrid.ItemContainerGenerator.Items[_prevRowIndex] as NotifiedPositionInfo;
        PositionsGrid.Items.RemoveAt(_prevRowIndex);
        PositionsGrid.Items.Insert(index, prev_position);

异常的内容是:

未处理的异常:System.InvalidOperationException:使用 ItemsSource 时操作无效。改为使用 ItemsControl.ItemsSource 访问和修改元素。

在 System.Windows.Controls.ItemCollection.CheckIsUsingInnerView()

在 System.Windows.Controls.ItemCollection.RemoveAt(Int32 removeIndex)

工作样本:

    <DataGrid Name="PositionsGrid" Background="AliceBlue" AutoGenerateColumns="False" CanUserAddRows="False" ItemsSource="{Binding}"
              AllowDrop="True" GridLinesVisibility="Horizontal" HorizontalGridLinesBrush="#FFDEDEDE">
        <DataGrid.Resources>
            <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#FF0096FD"/>
        </DataGrid.Resources>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Product Name" Width="130" IsReadOnly="True" Binding="{Binding ProductName}"/>
            <DataGridTextColumn Header="Positions" Width="*" IsReadOnly="True" Binding="{Binding Position}"/>
        </DataGrid.Columns>
    </DataGrid>

拖动功能:

    PositionsGrid.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(positionsGrid_PreviewMouseLeftButtonDown);
    PositionsGrid.Drop += new DragEventHandler(positionsGrid_Drop);

    private bool isTheMouseOnTargetRow(Visual target, GetDragDropPosition pos)
    {
        try
        {
            Rect posBounds = VisualTreeHelper.GetDescendantBounds(target);
            Point theMousePos = pos((IInputElement)target);
            return posBounds.Contains(theMousePos);
        }
        catch (Exception)
        {
            return false;
        }
    }

    private DataGridRow getDataGridRowItem(int index)
    {
        if (PositionsGrid.ItemContainerGenerator.Status != System.Windows.Controls.Primitives.GeneratorStatus.ContainersGenerated)
            return null;

        return PositionsGrid.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;
    }

    private int getDataGridItemCurrentRowIndex(GetDragDropPosition pos)
    {
        int curIndex = -1;
        for (int i = 0; i < PositionsGrid.Items.Count; i++)
        {
            DataGridRow item = getDataGridRowItem(i);
            if (isTheMouseOnTargetRow(item, pos))
            {
                curIndex = i;
                break;
            }
        }
        return curIndex;
    }

    private int _prevRowIndex = -1;

    private void positionsGrid_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        _prevRowIndex = getDataGridItemCurrentRowIndex(e.GetPosition);

        if (_prevRowIndex < 0)
            return;

        PositionsGrid.SelectedIndex = _prevRowIndex;

        NotifiedPositionInfo selected_positionInfo = PositionsGrid.Items[_prevRowIndex] as NotifiedPositionInfo;

        if (selected_positionInfo == null)
            return;

        DragDropEffects dragdrop_effects = DragDropEffects.Move;

        if (DragDrop.DoDragDrop(PositionsGrid, selected_positionInfo, dragdrop_effects) != DragDropEffects.None)
            PositionsGrid.SelectedItem = selected_positionInfo;
    }

    private void positionsGrid_Drop(object sender, DragEventArgs e)
    {
        if (_prevRowIndex < 0)
            return;

        int index = this.getDataGridItemCurrentRowIndex(e.GetPosition);

        if (index < 0)
            return;

        if (index == _prevRowIndex)
            return;

        if (index == PositionsGrid.Items.Count - 1)
        {
            MessageBox.Show("This row-index cannot be used for Drop Operations");
            return;
        }

        NotifiedPositionInfo prev_position = PositionsGrid.ItemContainerGenerator.Items[_prevRowIndex] as NotifiedPositionInfo;
        PositionsGrid.Items.RemoveAt(_prevRowIndex);
        PositionsGrid.Items.Insert(index, prev_position);
    }

【问题讨论】:

  • 尝试移入_productsPosition 收藏。也许通过使用某种排序属性而不是移动实际元素。
  • 排序顺序属性?你能详细描述一下吗?谢谢!!
  • 默认情况下没有这样的属性,但您可以在NotifiedPositionInfo 类中实现自己的属性并使用CollectionViewSource 提供相同的排序视图。您可以发布工作样本吗?我可以尝试在你的代码中做同样的事情吗?
  • 其实,当我们使用wpf默认datagrid的header排序时,collectionview的顺序和collection的顺序是不同的。你可以假设我想在我们使用标题排序后拖动行。拖拽功能可以看这里link。非常感谢!!!
  • 你的情况有点复杂。顺便说一句,您可以发布工作样本吗?我可以看看这里吗?

标签: wpf drag itemssource icollectionview


【解决方案1】:

好的,最后我用一个不聪明的操作解决了这个问题。我在集合视图上拖动特定元素时重置集合中的位置。此外,我更改了排序事件,确保 collectionView 不会控制绑定到集合的显示。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-03-07
    • 1970-01-01
    • 2018-07-16
    • 1970-01-01
    • 2014-10-05
    • 2017-04-12
    • 2017-04-18
    • 1970-01-01
    相关资源
    最近更新 更多