绑定到集合的Icollectionview上的wpf datagrid拖动行 [英] wpf datagrid drag row on Icollectionview which bind to collection

查看:247
本文介绍了绑定到集合的Icollectionview上的wpf datagrid拖动行的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这样的数据网格

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

当我尝试在此datagrid上拖动行时,我可以在collectionview上获取行的索引。但是此索引不能帮助我在集合_productsPosition中获得相同的元素,因为collectionView已由过滤器修改。

and when I try to drag row on this datagrid, i can obtain the index of row on the collectionview. But this index can not help me get the same element in the collection _productsPosition, because the collectionView was modified by the filter.

因此,我有一个问题,我该如何只需将元素移动到collectionview上,而不是_productsPosition。这样的事情会引发异常:

Therefore, i have a question that how can i just move elements on the collectionview but not _productsPosition. Something like this which throws exception:

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

例外内容为:

未处理的异常:System.InvalidOperationException:使用ItemsSource时操作无效。

Unhandled Exception: System.InvalidOperationException: Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.

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

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

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

at 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);
    }


推荐答案

好的,最后我解决了这个问题操作不灵巧的问题。当特定元素在集合视图中拖动时,我将其重置。此外,我更改排序事件以确保collectionView不会控制绑定到该集合的显示。

ok, finally i solve this problem with a not clever operation. I reset the specific element's position in the collection while it is dragged on the collectionview. Besides, i change the sorting event make sure the collectionView will not controll the display which binds to the collection.

这篇关于绑定到集合的Icollectionview上的wpf datagrid拖动行的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆