问题
I have a datagrid like this
_productsPosition = new ObservableCollectionEx<NotifiedPositionInfo>();
_itemSourceList = new CollectionViewSource() { Source = _productsPosition };
_itemSourceList.Filter += new FilterEventHandler(FilteringProduct);
PositionsGrid.ItemsSource = _itemSourceList.View;
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.
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);
the content of exception is:
Unhandled Exception: System.InvalidOperationException: Operation is not valid while ItemsSource is in use. Access and modify elements with ItemsControl.ItemsSource instead.
at System.Windows.Controls.ItemCollection.CheckIsUsingInnerView()
at System.Windows.Controls.ItemCollection.RemoveAt(Int32 removeIndex)
Working sample:
<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>
Drag function:
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);
}
回答1:
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.
来源:https://stackoverflow.com/questions/24879863/wpf-datagrid-drag-row-on-icollectionview-which-bind-to-collection