winforms 使用拖放功能对DevExpress GridControl中的分组行重新排序

lc8prwob  于 2023-03-31  发布在  其他
关注(0)|答案(3)|浏览(293)

我在my WinForms project中使用DevExpress控件。我需要通过使用BehaviorManager拖放来重新排序组行(包括其详细信息)(除了重新排序详细信息中的行)。对于拖放行,我编写了以下代码:

private void Behavior_DragOver(object sender, DragOverEventArgs e) 
{
        DragOverGridEventArgs args = DragOverGridEventArgs.GetDragOverGridEventArgs(e);
        e.InsertType = args.InsertType;
        e.InsertIndicatorLocation = args.InsertIndicatorLocation;
        e.Action = args.Action;
        Cursor.Current = args.Cursor;
        args.Handled = true;
}
private void Behavior_DragDrop(object sender, DragDropEventArgs e) 
{
        GridView targetGrid = e.Target as GridView;
        GridView sourceGrid = e.Source as GridView;
        if (e.Action == DragDropActions.None || targetGrid != sourceGrid)
            return;
        DataTable sourceTable = sourceGrid.GridControl.DataSource as DataTable;

        Point hitPoint = targetGrid.GridControl.PointToClient(Cursor.Position);
        GridHitInfo hitInfo = targetGrid.CalcHitInfo(hitPoint);

        int[] sourceHandles = e.GetData<int[]>();

        int targetRowHandle = hitInfo.RowHandle;
        int targetRowIndex = targetGrid.GetDataSourceRowIndex(targetRowHandle);

        List<DataRow> draggedRows = new List<DataRow>();
        foreach (int sourceHandle in sourceHandles) {
            int oldRowIndex = sourceGrid.GetDataSourceRowIndex(sourceHandle);
            DataRow oldRow = sourceTable.Rows[oldRowIndex];
            draggedRows.Add(oldRow);
        }

        int newRowIndex;

        switch (e.InsertType) {
            case InsertType.Before:
                newRowIndex = targetRowIndex > sourceHandles[sourceHandles.Length - 1]
                ? targetRowIndex - 1 : targetRowIndex;
                for (int i = draggedRows.Count - 1; i >= 0; i--) {
                    DataRow oldRow = draggedRows[i];
                    DataRow newRow = sourceTable.NewRow();
                    newRow.ItemArray = oldRow.ItemArray;
                    sourceTable.Rows.Remove(oldRow);
                    sourceTable.Rows.InsertAt(newRow, newRowIndex);
                }
                break;
            case InsertType.After:
                newRowIndex = targetRowIndex < sourceHandles[0] 
                ? targetRowIndex + 1 : targetRowIndex;
                for (int i = 0; i < draggedRows.Count; i++) {
                    DataRow oldRow = draggedRows[i];
                    DataRow newRow = sourceTable.NewRow();
                    newRow.ItemArray = oldRow.ItemArray;
                    sourceTable.Rows.Remove(oldRow);
                    sourceTable.Rows.InsertAt(newRow, newRowIndex);
                }
                break;
            default:
                newRowIndex = -1;
                break;
        }
        int insertedIndex = targetGrid.GetRowHandle(newRowIndex);
        targetGrid.FocusedRowHandle = insertedIndex;
        targetGrid.SelectRow(targetGrid.FocusedRowHandle);
   }

例如,我想通过拖放替换Level3和Level6组行的位置。
我该怎么做?

fnatzsnv

fnatzsnv1#

这个答案使用了一个自定义的GridViewEx类,它继承自GridView,允许以一种干净的方式实现使用拖放重新排序分组行的目标,而不会在主窗体中混入大量代码。您的帖子和附加评论陈述了两个要求,我还添加了第三个目标,使外观和感觉与记录中已经存在的拖放功能相似。

  • 目标行之前或之后
  • 展开的行保持展开状态
  • 拖动反馈类似于记录版本

此自定义版本只需在Designer.cs文件中手动换出即可。

在该示例中,反馈线对于“目标行之前”为蓝色,并且对于“目标行之后”为红色。

在操作之前展开的组将保持该状态。

GridViewEx-clone可以从GitHub获得演示项目。

GridViewEx维护自己的GroupDragDropState以避免与BehaviorManager操作的潜在冲突。

enum GroupDragDropState
{
    None,
    Down,
    Drag,
    Drop,
}

如果鼠标按下光标在任何方向移动超过10个位置,则进入Drag状态。

internal class GridViewEx : GridView
{
    public GridViewEx()
    {
        MouseDown += OnMouseDown;
        MouseMove += OnMouseMove;
        MouseUp += OnMouseUp;
        CustomDrawGroupRow += OnCustomDrawGroupRow;
        DataSourceChanged += OnDataSourceChanged;
        DisableCurrencyManager = true; // Use this setting From sample code.
        GroupRowCollapsing += OnGroupRowCollapsing;
        CustomColumnSort += OnCustomColumnSort;
    }

    protected virtual void OnMouseDown(object sender, MouseEventArgs e)
    {
        var hittest = CalcHitInfo(e.Location);
        var screenLocation = PointToScreen(e.Location);
        _mouseDownClient = e.Location;
        _isGroupRow = hittest.RowInfo != null && hittest.RowInfo.IsGroupRow;
        if (_isGroupRow)
        {
            var gridGroupInfo = (GridGroupRowInfo)hittest.RowInfo;
            _dragFeedbackLabel.RowBounds = hittest.RowInfo.Bounds.Size;
            DragRowInfo = gridGroupInfo;
            _isExpanded = gridGroupInfo.IsGroupRowExpanded;
        }
    }

    protected virtual void OnMouseMove(object sender, MouseEventArgs e)
    {
        if (Control.MouseButtons.Equals(MouseButtons.Left))
        {
            _mouseDeltaX = _mouseDownClient.X - e.Location.X;
            _mouseDeltaY = _mouseDownClient.Y - e.Location.Y;
            if (Math.Abs(_mouseDeltaX) > 10 || Math.Abs(_mouseDeltaY) > 10)
            {
                GroupDragDropState = GroupDragDropState.Drag;
            }
            var hittest = CalcHitInfo(e.Location);
            if ((hittest.RowInfo == null) || hittest.RowInfo.Equals(DragRowInfo) || !hittest.RowInfo.IsGroupRow)
            {
                CurrentGroupRowInfo = null;
            }
            else
            {
                CurrentGroupRowInfo = (GridGroupRowInfo)hittest.RowInfo;
                var deltaY = e.Location.Y - CurrentGroupRowInfo.Bounds.Location.Y;
                var mid = CurrentGroupRowInfo.Bounds.Height / 2;
                DropBelow = deltaY >= mid;
            }
        }
    }

    protected virtual void OnMouseUp(object sender, MouseEventArgs e)
    {
        switch (GroupDragDropState)
        {
            case GroupDragDropState.None:
                break;
            case GroupDragDropState.Down:
                GroupDragDropState = GroupDragDropState.None;
                break;
            case GroupDragDropState.Drag:
                GroupDragDropState = GroupDragDropState.Drop;
                break;
            case GroupDragDropState.Drop:
                GroupDragDropState = GroupDragDropState.None;
                break;
        }
    }
    private Point _mouseDownClient = Point.Empty;
    private int _mouseDeltaX = 0;
    private int _mouseDeltaY = 0;
    .
    .
    .
}

拖拽反馈

进入拖动状态会对点击的行进行屏幕截图。* 为了确保 * Graphics.CopyFromScreen * 方法的正确操作,appconfig.cs已被修改为逐屏DPI感知 *。
appconfig.cs

<?xml version="1.0"?>
<configuration>
    <startup>   
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.8"/>
    </startup>
    <System.Windows.Forms.ApplicationConfigurationSection>
        <add key="DpiAwareness" value="PerMonitorV2" />
    </System.Windows.Forms.ApplicationConfigurationSection>
</configuration>

GridViewEx.cs

protected virtual void OnGroupDragDropStateChanged()
{
    switch (GroupDragDropState)
    {
        case GroupDragDropState.None:
            break;
        case GroupDragDropState.Down:
            break;
        case GroupDragDropState.Drag:
            if (_isGroupRow)
            {
                getRowScreenshot();
            }
            _dragFeedbackLabel.Visible = true;
            break;
        case GroupDragDropState.Drop:
            _dragFeedbackLabel.Visible = false;
            OnDrop();
            break;
        default:
            break;
    }
}

void getRowScreenshot()
{
    // MUST be set to DPI AWARE in config.cs
    var ctl = GridControl;
    var screenRow = ctl.PointToScreen(DragRowInfo.Bounds.Location);
    var screenParent = ctl.TopLevelControl.Location;

    using (var srceGraphics = ctl.CreateGraphics())
    {
        var size = DragRowInfo.Bounds.Size;

        var bitmap = new Bitmap(size.Width, size.Height, srceGraphics);
        var destGraphics = Graphics.FromImage(bitmap);
        destGraphics.CopyFromScreen(screenRow.X, screenRow.Y, 0, 0, size);
        _dragFeedbackLabel.BackgroundImage = bitmap;
    }
}

此图像被分配给_dragFeedbackLabel成员的BackgroundImage,该成员是一个无边框窗体,可以在主窗体的矩形外部绘制。当可见时,此窗体通过MessageFilter拦截WM_MOUSEMOVE消息来跟踪鼠标光标的移动。

class DragFeedback : Form, IMessageFilter
{
    const int WM_MOUSEMOVE = 0x0200;

    public DragFeedback()
    {
        StartPosition = FormStartPosition.Manual;
        FormBorderStyle = FormBorderStyle.None;
        BackgroundImageLayout = ImageLayout.Stretch;
        Application.AddMessageFilter(this);
        Disposed += (sender, e) => Application.RemoveMessageFilter(this);
    }

    protected override void SetBoundsCore(int x, int y, int width, int height, BoundsSpecified specified)
    {
        if (RowBounds == null)
        {
            base.SetBoundsCore(x, y, width, height, specified);
        }
        else
        {
            base.SetBoundsCore(x, y, RowBounds.Width, RowBounds.Height, specified);
        }
    }

    public bool PreFilterMessage(ref Message m)
    {
        if(MouseButtons == MouseButtons.Left && m.Msg.Equals(WM_MOUSEMOVE)) 
        {
            Location = MousePosition;
        }
        return false;
    }

    Point _mouseDownPoint = Point.Empty;
    Point _origin = Point.Empty;

    public Size RowBounds { get; internal set; }
    public new Image BackgroundImage
    {
        get => base.BackgroundImage;
        set
        {
            if((value == null) || (base.BackgroundImage == null))
            {
                base.BackgroundImage = value;
            }
        }
    }
    protected override void OnVisibleChanged(EventArgs e)
    {
        base.OnVisibleChanged(e);
        if(!Visible)
        {
            base.BackgroundImage?.Dispose(); ;
            base.BackgroundImage = null;
        }
    }
}

行分隔符是通过处理GridView.CustomDrawGroupRow事件绘制的。

protected virtual void OnCustomDrawGroupRow(object sender, RowObjectCustomDrawEventArgs e)
{
    if (e.Info is GridRowInfo ri)
    {
        using (var pen = new Pen(DropBelow ? Brushes.LightSalmon : Brushes.Aqua, 4F))
        {
            switch (GroupDragDropState)
            {
                case GroupDragDropState.Drag:
                    if (CurrentGroupRowInfo != null)
                    {
                        if (ri.RowHandle == CurrentGroupRowInfo.RowHandle)
                        {
                            e.DefaultDraw();
                            int y;
                            if (DropBelow)
                            {
                                y = ri.Bounds.Y + CurrentGroupRowInfo.Bounds.Height - 2;
                            }
                            else
                            {
                                y = ri.Bounds.Y + 1;
                            }
                            e.Graphics.DrawLine(pen,
                                ri.Bounds.X, y,
                                ri.Bounds.X + ri.Bounds.Width, y);
                            e.Handled = true;
                        }
                    }
                    break;
            }
        }
    }
}

DropBelow值在目标行更改时在拖动 * 或 * 的中点处切换时,需要重新绘制受影响的行。

public bool DropBelow
{
    get => _dropBelow;
    set
    {
        if (!Equals(_dropBelow, value))
        {
            _dropBelow = value;
#if true
            // "Minimal redraw" version
            RefreshRow(CurrentGroupRowInfo.RowHandle);
#else
            // But if drawing artifacts are present, refresh
            // the entire control surface instead.
            GridControl.Refresh();
#endif
        }
    }
}
bool _dropBelow = false;

OnDrop

删除记录的ItemsArray被隐藏在字典中,以便在新索引处插入相同的DataRow示例之前进行重新分配。根据MouseMove处理程序中设置的DropBelow布尔值对插入操作进行调整。

protected virtual void OnDrop()
{
    var dataTable = (DataTable)GridControl.DataSource;
    if (!((DragRowInfo == null) || (CurrentGroupRowInfo == null)))
    {
        Debug.WriteLine($"{DragRowInfo.GroupValueText} {CurrentGroupRowInfo.GroupValueText}");
        var drags =
            dataTable
            .Rows
            .Cast<DataRow>()
            .Where(_ => _[CurrentGroupRowInfo.Column.FieldName]
            .Equals(DragRowInfo.EditValue)).ToArray();

        var dict = new Dictionary<DataRow, object[]>();
        foreach (var dataRow in drags)
        {
            dict[dataRow] = dataRow.ItemArray;
            dataTable.Rows.Remove(dataRow);
        }

        DataRow receiver =
            dataTable
            .Rows
            .Cast<DataRow>()
            .FirstOrDefault(_ =>
                _[CurrentGroupRowInfo.Column.FieldName]
                .Equals(CurrentGroupRowInfo.EditValue));
        int insertIndex;

        if (DropBelow)
        {
            receiver =
                dataTable
                .Rows
                .Cast<DataRow>()
                .LastOrDefault(_ =>
                    _[CurrentGroupRowInfo.Column.FieldName]
                    .Equals(CurrentGroupRowInfo.EditValue));

            insertIndex = dataTable.Rows.IndexOf(receiver) + 1;
        }
        else
        {
            receiver =
                dataTable
                .Rows
                .Cast<DataRow>()
                .FirstOrDefault(_ =>
                    _[CurrentGroupRowInfo.Column.FieldName]
                    .Equals(CurrentGroupRowInfo.EditValue));

            insertIndex = dataTable.Rows.IndexOf(receiver);
        }
        foreach (var dataRow in drags.Reverse())
        {
            dataRow.ItemArray = dict[dataRow];
            dataTable.Rows.InsertAt(dataRow, insertIndex);
        }
        try
        {
            var parentRowHandle = GetParentRowHandle(insertIndex);
            if (_isExpanded)
            {
                ExpandGroupRow(parentRowHandle);
            }
            FocusedRowHandle = parentRowHandle;
        }
        catch (Exception ex)
        {
            Debug.Assert(false, ex.Message);
        }
    }
}

杂项

GridViewEx采用了一种只启用自定义排序的总括方法,初步测试表明,当前形式的拖放对于关键字分组的工作原理与对于级别的工作原理相同。

/// <summary>
/// Disable automatic sorting. 
/// </summary>
protected virtual void OnDataSourceChanged(object sender, EventArgs e)
{
    foreach (GridColumn column in Columns)
    {
        column.SortMode = ColumnSortMode.Custom;
    }
    ExpandGroupLevel(1);
}

protected virtual void OnCustomColumnSort(object sender, CustomColumnSortEventArgs e)
{
    e.Handled = true;
}

/// <summary>
/// Disallow collapses during drag operations
/// </summary>
protected virtual void OnGroupRowCollapsing(object sender, RowAllowEventArgs e)
{
    e.Allow = GroupDragDropState.Equals(GroupDragDropState.None);
}
ecr0jaav

ecr0jaav2#

我尝试了一些修改,但是没有通过BehaviorManager成功应用,最后我使用了网格控件grid_DragDropgrid_DragOverview_MouseDownview_MouseMove事件代替了行为管理器,另外我在SetUpGrid函数中添加了一些代码行。

public void SetUpGrid(GridControl grid, DataTable table) {
        GridView view = grid.MainView as GridView;
        grid.DataSource = table;
        view.OptionsBehavior.Editable = false;
        view.Columns["Level"].GroupIndex = 1;
        
        //new codes
        gridControl1.AllowDrop = true;
        grid.DragDrop += grid_DragDrop;
        grid.DragOver += grid_DragOver;
        view.MouseDown += view_MouseDown;
        view.MouseMove += view_MouseMove;
    }

    void view_MouseDown(object sender, MouseEventArgs e)
    {
        GridView view = sender as GridView;
        downHitInfo = null;
        GridHitInfo hitInfo = view.CalcHitInfo(new Point(e.X, e.Y));
        if (Control.ModifierKeys != Keys.None) return;
        if ((e.Button == MouseButtons.Left || e.Button == MouseButtons.Right) && hitInfo.RowHandle >= 0)
            downHitInfo = hitInfo;
    }

    void view_MouseMove(object sender, MouseEventArgs e)
    {
        GridView view = sender as GridView;
        if (e.Button == MouseButtons.Left && downHitInfo != null)
        {
            Size dragSize = SystemInformation.DragSize;
            Rectangle dragRect = new Rectangle(new Point(downHitInfo.HitPoint.X - dragSize.Width / 2,
                downHitInfo.HitPoint.Y - dragSize.Height / 2), dragSize);
            if (!dragRect.Contains(new Point(e.X, e.Y)))
            {
                DataTable table = view.GridControl.DataSource as DataTable;
                int[] rows = view.GetSelectedRows();
                List<DataRow> rwlist = new List<DataRow>();
                for (int i = rows.Length - 1; i >= 0; i--)
                {
                    DataRowView rv = (DataRowView)gridView1.GetRow(rows[i]);
                    rwlist.Add(rv.Row);
                }
                view.GridControl.DoDragDrop(rwlist, DragDropEffects.Move);
                downHitInfo = null;
                DevExpress.Utils.DXMouseEventArgs.GetMouseArgs(e).Handled = true;
            }
        }
    }
    

    void grid_DragOver(object sender, DragEventArgs e)
    {
        if (e.Data.GetDataPresent(typeof(List<DataRow>)))
        {
            e.Effect = DragDropEffects.Move;
        }
        else
            e.Effect = DragDropEffects.None;
    }

    GridHitInfo downHitInfo = null;
    void grid_DragDrop(object sender, DragEventArgs e)
    {
        GridControl grid = sender as GridControl;
        DataTable table = grid.DataSource as DataTable;
        GridView view = grid.MainView as GridView;
        Point pt = grid.PointToClient(new Point(e.X, e.Y));
        GridHitInfo hitInfo = view.CalcHitInfo(pt);
        int sourceRow = downHitInfo.RowHandle;
        int targetRow = hitInfo.RowHandle;
        List<DataRow> rows = e.Data.GetData(typeof(List<DataRow>)) as List<DataRow>;

        DataRowView drV = view.GetRow(targetRow >= 0 ? targetRow : sourceRow) as DataRowView;
        object TargetLevel = drV.Row["Level"];

        foreach (DataRow row in rows)
        {
            if (row.Table != table)
            {
                continue;
            }
            if (view.SortInfo.GroupCount > 0)
            {
                if (view.SortInfo.GroupCount == 1)
                {
                    if (view.GroupedColumns[0].FieldName != "Level")
                        return;
                }
                else
                    return;
            }
            if (targetRow < 0)
                return;
            if (targetRow == sourceRow)
            {
                return;
            }
            DataRow newRow = table.NewRow() as DataRow;
            newRow.ItemArray = row.ItemArray;
            newRow["Level"] = TargetLevel;
            if (targetRow >= 0)
            {
                row.Delete();
            }
            int to = targetRow;
            if (table.Rows.Count == to)
            {
                if (sourceRow >= targetRow)
                    to = table.Rows.Count - 1;
            }
            table.Rows.InsertAt(newRow, to);
            if (sourceRow < targetRow) targetRow--;

        }
    }
ecfsfe2w

ecfsfe2w3#

当一个列被分组时,它也同时被排序。因此,你必须阻止排序(至少对于Level列)。我这里有一个没有BehaviorManager的旧版本DevExpress。但是你也可以用这个旧版本实现这个行为。
您可以使用DragDropDragOverMouseDownMouseMove(类似于muludag answer)。拖放操作仅适用于分组列Level通过PinBack更新):

public class LevelDragDropInfo
{
    public GridHitInfo DragDropHitInfo { get; set; }
    public decimal Level { get; set; }
    public List<decimal> LevelExpanded { get; private set; }

    public void SnapShotGroups(GridView poGridView)
    {
        this.LevelExpanded = new List<decimal>();

        if (poGridView.GroupedColumns.Count > 0)
        {
            for (int i = -1; poGridView.IsValidRowHandle(i); i--)
            {
                if (poGridView.GetRowExpanded(i))
                {
                    var loRow = poGridView.GetDataRow(poGridView.GetDataRowHandleByGroupRowHandle(i)) as DataRow;
                    if (loRow != null)
                    {
                        this.LevelExpanded.Add(loRow.Field<decimal>("Level"));
                    }

                }
            }
        }
    }

    public void RestoreGroups(GridView poGridView)
    {
        poGridView.CollapseAllGroups();
        if (this.LevelExpanded?.Count > 0)
        {
            for (int i = -1; poGridView.IsValidRowHandle(i); i--)
            {
                var loRow = poGridView.GetDataRow(poGridView.GetDataRowHandleByGroupRowHandle(i)) as DataRow;
                if (loRow != null &&
                    this.LevelExpanded.Contains(loRow.Field<decimal>("Level")))
                {
                    poGridView.SetRowExpanded(i, true, false);
                }
            }
        }
    }

}

private LevelDragDropInfo moLevelDragDropInfo;

public void SetUpGrid(GridControl grid, DataTable table)
{
    GridView view = grid.MainView as GridView;
    grid.DataSource = table;
    grid.AllowDrop = true;
    view.OptionsBehavior.Editable = false;

    view.Columns["Level"].SortMode = ColumnSortMode.Custom;
    //Prevent Sorting on Grouping
    view.CustomColumnSort += this.View_CustomColumnSort;
    view.Columns["Level"].GroupIndex = 1;
   
    //Drag/Drop Events
    grid.DragDrop += this.Grid_DragDrop;
    grid.DragOver += this.Grid_DragOver;
    view.MouseDown += this.View_MouseDown;
    view.MouseMove += this.View_MouseMove;
}

private void View_CustomColumnSort(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnSortEventArgs e)
{
    if (e.Column.FieldName == "Level")
    {
        e.Handled = true;
    }
}

public void View_MouseDown(object sender, MouseEventArgs e)
{
    this.moLevelDragDropInfo = null;

    GridView loView = sender as GridView;
    GridHitInfo loHitInfo = loView.CalcHitInfo(new Point(e.X, e.Y));

    if (e.Button == MouseButtons.Left
        && loHitInfo.InGroupRow
        && loHitInfo.RowInfo is GridGroupRowInfo)
    {
        if (loHitInfo.RowInfo is GridGroupRowInfo loGridGroupRowInfo)
        {
            if (loGridGroupRowInfo.RowKey is DevExpress.Data.GroupRowInfo loGroupRowInfo)
            {
                this.moLevelDragDropInfo = new LevelDragDropInfo()
                {
                    DragDropHitInfo = loHitInfo,
                    Level = Convert.ToDecimal(loGroupRowInfo.GroupValue)
                };
            }
        }
    }
}

private void View_MouseMove(object sender, MouseEventArgs e)
{
    GridView loView = sender as GridView;
    if (this.moLevelDragDropInfo != null && e.Button == MouseButtons.Left)
    {
        System.Drawing.Point loPoint = new System.Drawing.Point(e.X, e.Y);
        if ((Math.Abs(loPoint.X - this.moLevelDragDropInfo.DragDropHitInfo.HitPoint.X) > 5 || Math.Abs(loPoint.Y - this.moLevelDragDropInfo.DragDropHitInfo.HitPoint.Y) > 5))
        {
            loView.GridControl.DoDragDrop(this.moLevelDragDropInfo, DragDropEffects.All);
        }
    }
}

private void Grid_DragOver(object sender, DragEventArgs e)
{
    GridControl loGrid = sender as GridControl;
    GridView loView = loGrid.MainView as GridView;
    GridHitInfo loDropHitInfo = loView.CalcHitInfo(loGrid.PointToClient(new Point(e.X, e.Y)));

    if (e.Data.GetDataPresent(typeof(LevelDragDropInfo)) &&
        (loDropHitInfo.InGroupRow || loDropHitInfo.InDataRow))
    {
        e.Effect = DragDropEffects.Move;
        return;
    }

    e.Effect = DragDropEffects.None;
}

private void Grid_DragDrop(object sender, DragEventArgs e)
{
    try
    {
        GridControl loGrid = sender as GridControl;
        DataTable loDataTable = loGrid.DataSource as DataTable;
        GridView loView = loGrid.MainView as GridView;
        GridHitInfo loDropHitInfo = loView.CalcHitInfo(loGrid.PointToClient(new Point(e.X, e.Y)));
        LevelDragDropInfo loLevelDragDropInfo = e.Data.GetData(typeof(LevelDragDropInfo)) as LevelDragDropInfo;
        GridGroupRowInfo loDropGroupRowInfo = loDropHitInfo.RowInfo as GridGroupRowInfo;
        GridDataRowInfo loDropDataRowInfo = loDropHitInfo.RowInfo as GridDataRowInfo;
        decimal? lnLevelTo = null;

        if (loDropGroupRowInfo != null)
        {
            lnLevelTo = Convert.ToDecimal((loDropGroupRowInfo.RowKey as DevExpress.Data.GroupRowInfo).GroupValue);
        }
        else if (loDropDataRowInfo != null)
        {
            DataRow loRow = loView.GetDataRow(loDropDataRowInfo.RowHandle) as DataRow;
            if (loRow != null)
            {
                lnLevelTo = loRow.Field<decimal>("Level");
            }
        }

        if (loLevelDragDropInfo != null && lnLevelTo.HasValue)
        {
            decimal lnLevelFrom = loLevelDragDropInfo.Level;
            List<object[]> loMoveRows = new List<object[]>();

            if (lnLevelFrom == lnLevelTo)
                return;

            loLevelDragDropInfo.SnapShotGroups(loView);

            //Remove from Table
            foreach (DataRow loRow in loDataTable.Rows.Cast<DataRow>().ToList())
            {
                if (loRow.Field<decimal>("Level") == lnLevelFrom)
                {
                    loMoveRows.Add(loRow.ItemArray);
                    loDataTable.Rows.Remove(loRow);
                }
            }

            //Insert before
            //int lnInsertIndex = loDataTable.Rows.IndexOf(loDataTable.Rows
            //    .Cast<DataRow>()
            //    .First(item => item.Field<decimal>("Level") == lnLevelTo));

            //Insert after
            int lnInsertIndex = loDataTable.Rows.IndexOf(loDataTable.Rows
                .Cast<DataRow>()
                .Last(item => item.Field<decimal>("Level") == lnLevelTo)) + 1;

            loMoveRows.Reverse();
            foreach (var loValues in loMoveRows)
            {
                DataRow loNewRow = loDataTable.NewRow();
                loNewRow.ItemArray = loValues;
                loDataTable.Rows.InsertAt(loNewRow, lnInsertIndex);
            }

            loLevelDragDropInfo.RestoreGroups(loView);
            this.moLevelDragDropInfo = null;
        }
    }
    catch (Exception exp)
    {
        MessageBox.Show(exp.ToString());
    }
}

由Masoud编辑:

通过以下更改,我们可以重新排序分组的行和行两者:

private void View_MouseDown(object sender, MouseEventArgs e)
 {
        this.moDragDropHitInfo = null;

        GridView loView = sender as GridView;
        GridHitInfo loHitInfo = loView.CalcHitInfo(new Point(e.X, e.Y));

        this.moDragDropHitInfo = loHitInfo;

        if (moDragDropHitInfo.InRowCell)
        {
            gridControl1.AllowDrop = false;
        }
        else if (moDragDropHitInfo.InGroupRow)
        {
            gridControl1.AllowDrop = true;
        }
 }

 private void View_MouseMove(object sender, MouseEventArgs e)
 {
        GridView loView = sender as GridView;
        if (this.moDragDropHitInfo != null && e.Button == MouseButtons.Left)
        {
            System.Drawing.Point loPoint = new System.Drawing.Point(e.X, e.Y);
            if ((Math.Abs(loPoint.X - this.moDragDropHitInfo.HitPoint.X) > 5 || Math.Abs(loPoint.Y - this.moDragDropHitInfo.HitPoint.Y) > 5))
            {
                if (this.moDragDropHitInfo.RowInfo is GridGroupRowInfo)
                {
                    gridControl1.AllowDrop = true;
                    loView.GridControl.DoDragDrop(this.moDragDropHitInfo.RowInfo as GridGroupRowInfo, DragDropEffects.All);
                }
                else
                {
                    gridControl1.AllowDrop = false;
                }
            }
        }
  }

相关问题