DragAbleDataGridView

行のドラッグ&ドロップが可能なDataGridView
ちょっとバグがあるけれど一応動作する。
DataSourceには対応できない。
ViewのCellに直接データを突っ込んで使用可能。


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing;


namespace MyReName.ctrl
{
    class DragAbleDataGridView : DataGridView
    {
        private int mintCurrentRowIndex = -1;
        private int mintNextRowIndex = -1;
        private bool mboolMoveToEndRowFlg = false;
        private int[] dragRowIndex;

        private bool Flg = true;

        private Label lblBar = new Label();
        public Color DropDawnBarColor
        {
            get
            {
                return lblBar.BackColor;
            }
            set
            {
                lblBar.BackColor = value;
            }
        }

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public DragAbleDataGridView()
        {
            this.InitCtrl();

        }

        /// <summary>
        /// コンポーネントの初期化処理
        /// </summary>
        private void InitCtrl()
        {

            // DataGridViewの初期設定
            this.AutoGenerateColumns = false;
            this.BackgroundColor = Color.White;
            this.CellBorderStyle = DataGridViewCellBorderStyle.None;
            this.RowHeadersVisible = false;
            this.AllowUserToResizeRows = false;
            this.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
            this.AllowUserToAddRows = false;
            this.AllowUserToDeleteRows = false;
            this.AllowDrop = true;
            this.ScrollBars = System.Windows.Forms.ScrollBars.Both;
            this.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.DisableResizing;
            this.ColumnHeadersDefaultCellStyle.WrapMode = DataGridViewTriState.False;

            // イベントを追加
            this.DragDrop += new DragEventHandler(DragAbleDataGridView_DragDrop);
            this.DragEnter += new DragEventHandler(DragAbleDataGridView_DragEnter);
            this.MouseDown += new MouseEventHandler(DragAbleDataGridView_MouseDown);
            this.MouseMove += new MouseEventHandler(DragAbleDataGridView_MouseMove);
            this.DragOver += new DragEventHandler(DragAbleDataGridView_DragOver);
            this.DragLeave += new EventHandler(DragAbleDataGridView_DragLeave);
            this.QueryContinueDrag += new QueryContinueDragEventHandler(DragAbleDataGridView_QueryContinueDrag);
            this.RowValidating += new DataGridViewCellCancelEventHandler(DragAbleDataGridView_RowValidating);

            // ドラッグ中に表示するバーを追加
            this.Controls.Add(lblBar);
            lblBar.Visible = false;
            lblBar.BackColor = Color.Red;
            lblBar.Size = new Size(this.Width, 2);
        }

        /// <summary>
        /// MouseDownイベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DragAbleDataGridView_MouseDown(object sender, MouseEventArgs e)
        {
            mintCurrentRowIndex = -1;

            // 左クリック以外はリターン
            if ((e.Button & MouseButtons.Left) != MouseButtons.Left)
            {
                return;
            }

            // セルクリック以外はリターン
            DataGridView.HitTestInfo hitInfo = this.HitTest(e.X, e.Y);
            if (hitInfo.Type != DataGridViewHitTestType.Cell)
            {
                return;
            }
            mintCurrentRowIndex = hitInfo.RowIndex;

            // 既に選択されているセルを選択している場合(ここの動作がうまくいかない…)
            if (this.Rows[mintCurrentRowIndex].Selected && ModifierKeys == Keys.None)
            {
                ReSetDragRowsIndexies();
                Flg = true;
            }
            // 未選択のセルを選択している場合
            else
            {
                dragRowIndex = null;
                Flg = false;
            }
        }

        /// <summary>
        /// 行の検証時の処理
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DragAbleDataGridView_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
        {
            if (Flg)
            {
                e.Cancel = true;
                Flg = false;
            }
        }

        /// <summary>
        /// MouseMoveイベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DragAbleDataGridView_MouseMove(object sender, MouseEventArgs e)
        {
            // 左ボタン以外はリターン
            if ((e.Button & MouseButtons.Left) != MouseButtons.Left)
            {
                return;
            }
            // Row未選択はリターン
            if (mintCurrentRowIndex == -1)
            {
                return;
            }
            // ドラッグ開始
            this.DoDragDrop(mintCurrentRowIndex, DragDropEffects.Move);
        }

        /// <summary>
        /// ドラッグ対象行のインデックスを記憶
        /// </summary>
        private void ReSetDragRowsIndexies()
        {
            dragRowIndex = new int[this.SelectedRows.Count];
            for (int i = 0; i < this.SelectedRows.Count; i++)
            {
                dragRowIndex[i] = this.SelectedRows[i].Index;
            }
        }

        /// <summary>
        /// DragOverイベント
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DragAbleDataGridView_DragOver(object sender, DragEventArgs e)
        {
            if (mintCurrentRowIndex == -1)
            {
                return;
            }
            e.Effect = DragDropEffects.Move;
            if (dragRowIndex == null)
            {
                ReSetDragRowsIndexies();
            }

            // ドラッグ位置を取得
            Point clientPoint = this.PointToClient(new Point(e.X, e.Y));
            DataGridView.HitTestInfo hitInfo = this.HitTest(clientPoint.X, clientPoint.Y);
            mboolMoveToEndRowFlg = false;
            if (hitInfo.RowIndex == -1)
            {
                if (mintCurrentRowIndex == this.Rows.Count - 1)
                {
                    mboolMoveToEndRowFlg = true;
                }
            }
            else
            {
                mintNextRowIndex = hitInfo.RowIndex;
            }

            if (mboolMoveToEndRowFlg)
            {
                Rectangle rec = this.GetRowDisplayRectangle(mintNextRowIndex, true);
                lblBar.Location = new Point(0, rec.Bottom);
                lblBar.Visible = true;
            }
            else if (mintCurrentRowIndex == mintNextRowIndex && mintCurrentRowIndex == this.Rows.Count - 1)
            {
                Rectangle rec = this.GetRowDisplayRectangle(mintNextRowIndex, true);
                lblBar.Location = new Point(0, rec.Top);
                lblBar.Visible = true;
            }
            else if (mintCurrentRowIndex != mintNextRowIndex)
            {
                Rectangle rec = this.GetRowDisplayRectangle(mintNextRowIndex, true);
                lblBar.Location = new Point(0, rec.Top);
                mintCurrentRowIndex = mintNextRowIndex;
                lblBar.Visible = true;
            }
        }

        /// <summary>
        /// DataGridViewの外へドラッグしたらドラッグをキャンセル
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DragAbleDataGridView_DragLeave(object sender, EventArgs e)
        {
            if (!lblBar.Visible)
            {
                return;
            }
            ExitDrag();
        }

        /// <summary>
        /// DragEnter
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DragAbleDataGridView_DragEnter(object sender, DragEventArgs e)
        {
            if (lblBar.Visible)
            {
                return;
            }
            e.Effect = DragDropEffects.All;
        }

        /// <summary>
        /// ドラッグ継続中
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DragAbleDataGridView_QueryContinueDrag(object sender, QueryContinueDragEventArgs e)
        {
            // 右クリック押下時
            if ((e.KeyState & 2) == 2)
            {
                // ドラッグをキャンセル
                e.Action = DragAction.Cancel;
                ExitDrag();
            }
        }

        /// <summary>
        /// 行データの移動
        /// </summary>
        /// <param name="FromIndex"></param>
        /// <param name="ToIndex"></param>
        /// <returns>実際の移動先インデックス</returns>
        private int MoveTo(int FromIndex, int ToIndex)
        {
            DataGridViewRow row;
            int MoveToIndex = ToIndex;
            if (FromIndex != ToIndex)
            {
                row = (DataGridViewRow)this.Rows[FromIndex].Clone();
                for (int i = 0; i < this.Columns.Count; i++)
                {
                    row.Cells[i].Value = this.Rows[FromIndex].Cells[i].Value;
                }

                if (FromIndex > ToIndex)
                {
                    this.Rows.RemoveAt(FromIndex);
                    this.Rows.Insert(ToIndex, row);
                }
                else if (FromIndex < ToIndex)
                {
                    if (mboolMoveToEndRowFlg)
                    {
                        this.Rows.RemoveAt(FromIndex);
                        this.Rows.Insert(ToIndex, row);
                    }
                    else
                    {
                        this.Rows.RemoveAt(FromIndex);
                        this.Rows.Insert(ToIndex - 1, row);
                        MoveToIndex = ToIndex - 1;
                    }
                }
            }
            return MoveToIndex;
        }

        private void DragAbleDataGridView_DragDrop(object sender, DragEventArgs e)
        {
            // 行のDragDropの場合
            if (lblBar.Visible)
            {
                Flg = false;
                Array.Sort(dragRowIndex);
                int ShiftFront = 0;
                int ShiftBack = 0;
                int MoveFromIndex = 0;
                int MoveToIndex = 0;
                int MinRowIndex = mintCurrentRowIndex;
                int MaxRowIndex = mintCurrentRowIndex;
                int SelectionStaIndex = 0;

                // 行を移動
                for (int i = 0; i < dragRowIndex.GetLength(0); i++)
                {
                    MoveFromIndex = dragRowIndex[i];
                    MoveToIndex = mintCurrentRowIndex;
                    if (MinRowIndex > MoveFromIndex)
                    {
                        MinRowIndex = MoveFromIndex;
                    }
                    else if (MinRowIndex > MoveToIndex)
                    {
                        MinRowIndex = MoveToIndex;
                    }

                    if (MaxRowIndex < MoveFromIndex)
                    {
                        MaxRowIndex = MoveFromIndex;
                    }
                    else if (MaxRowIndex < MoveToIndex)
                    {
                        MaxRowIndex = MoveToIndex;
                    }
                    if (i > 0)
                    {
                        if (MoveFromIndex < MoveToIndex)
                        {
                            ShiftFront--;
                            MoveFromIndex += ShiftFront;
                        }
                        else if (MoveFromIndex > MoveToIndex)
                        {
                            if (dragRowIndex[i - 1] >= MoveToIndex)
                            {
                                ShiftBack++;
                                MoveToIndex += ShiftBack;
                            }
                        }
                    }
                    if (i == 0)
                    {
                        SelectionStaIndex = MoveTo(MoveFromIndex, MoveToIndex);
                    }
                    else
                    {
                        MoveTo(MoveFromIndex, MoveToIndex);
                    }

                }

                // 移動後の行を選択
                this.CurrentCell = this.Rows[SelectionStaIndex + ShiftFront].Cells[0];
                this.ClearSelection();
                for (int i = 0; i < dragRowIndex.GetLength(0); i++)
                {
                    this.Rows[SelectionStaIndex + ShiftFront + i].Selected = true;
                }
                ExitDrag();
            }
            // DataGridView外からのDragDropの場合
            else
            {
                //DragDropされたファイルパスをセルに追加

                if (e.Data.GetDataPresent(DataFormats.FileDrop))
                {
                    foreach (string filePath in (string[])e.Data.GetData(DataFormats.FileDrop))
                    {
                        if (this.Columns.Count > 0)
                        {
                            this.Rows.Add();
                            this.Rows[this.Rows.Count - 1].Cells[0].Value = filePath;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// ドラッグの終了処理
        /// </summary>
        private void ExitDrag()
        {
            mintCurrentRowIndex = -1;
            //_DragMode = eDraggingMode.None;
            lblBar.Visible = false;
            this.DoDragDrop(mintCurrentRowIndex, DragDropEffects.None);
        }

    }
}
最終更新:2012年01月11日 00:26
ツールボックス

下から選んでください:

新しいページを作成する
ヘルプ / FAQ もご覧ください。