【C#/WinForms】タブコントロールのタブを移動可能にする方法

この記事は約10分で読めます。

標準のタブコントロールはタブの移動(入替え)はできません。そのため OnDragEnter、OnDragOver、OnDragDropイベント等で独自に実装します。 サンプルではドラッグでタブが移動しボタンを離すことでタブの入れ替えが可能です。

サンプルソース

TabControl を継承して実装します。

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

namespace Test {
    /// <summary>
    /// タブの移動可能タブコントロールサンプル
    /// </summary>
    public class TabControlEx : TabControl {

        private TabPage moveTabFrom = null;
        private TabPageCollection tabList = null;
        private Point mouseClickPoint;

        /// <summary>
        /// コンストラクタ
        /// </summary>
        public TabControlEx() {
        }

        /// <summary>
        /// OnDragEnter
        /// </summary>
        /// <param name="e"></param>
        protected override void OnDragEnter(DragEventArgs e) {
            base.OnDragEnter(e);
            Point pt = base.PointToClient(new Point(e.X, e.Y));
            TabPage moveTabTo = this.GetTabFromPoint(pt);
            if (moveTabTo == null || e.Data.GetData(this.moveTabFrom.GetType()) != this.moveTabFrom) {
                e.Effect = DragDropEffects.None;
            } else {
                e.Effect = DragDropEffects.Move;
            }
        }

        /// <summary>
        /// OnDragOver
        /// </summary>
        /// <param name="drgevent"></param>
        protected override void OnDragOver(DragEventArgs drgevent) {
            base.OnDragOver(drgevent);
            Point pt = base.PointToClient(new Point(drgevent.X, drgevent.Y));
            TabPage moveTabTo = this.GetTabFromPoint(pt);
            if (moveTabTo == null || drgevent.Data.GetData(this.moveTabFrom.GetType()) != this.moveTabFrom) {
                drgevent.Effect = DragDropEffects.None;
            } else {
                drgevent.Effect = DragDropEffects.Move;
            }
        }

        /// <summary>
        /// OnDragDrop
        /// </summary>
        /// <param name="drgevent"></param>
        protected override void OnDragDrop(DragEventArgs drgevent) {
            base.OnDragDrop(drgevent);
            Point pt = base.PointToClient(new Point(drgevent.X, drgevent.Y));
            TabPage moveTabTo = this.GetTabFromPoint(pt);
            int moveTabFromIdx = this.IndexOfTab(this.moveTabFrom);
            int moveTabToIdx = this.IndexOfTab(moveTabTo);
            if (moveTabFromIdx != moveTabToIdx) {
                base.SuspendLayout();
                if (moveTabFromIdx < moveTabToIdx) {
                    for (int i = moveTabFromIdx; i < moveTabToIdx; i++) {
                        base.TabPages[i] = base.TabPages[i + 1];
                    }
                } else if (moveTabToIdx < moveTabFromIdx) {
                    for (int i = moveTabFromIdx; moveTabToIdx < i; i--) {
                        base.TabPages[i] = base.TabPages[i - 1];
                    }
                }
                base.TabPages[moveTabToIdx] = this.moveTabFrom;
                base.SelectedTab = this.moveTabFrom;
                base.ResumeLayout();
            }
        }

        /// <summary>
        /// OnMouseDown
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e) {
            base.OnMouseDown(e);
            this.mouseClickPoint = new Point(e.X, e.Y);
            this.tabList = base.TabPages;
            this.moveTabFrom = this.GetTabFromPoint(this.mouseClickPoint);
            if (this.Appearance != TabAppearance.Normal) {
                if (this.moveTabFrom != null) {
                    this.SelectedTab = (this.moveTabFrom as TabPage);
                }
            }

        }

        /// <summary>
        /// OnMouseMove
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e) {
            base.OnMouseMove(e);
            if (e.Button == MouseButtons.Left) {
                if (this.mouseClickPoint.X != e.X || this.mouseClickPoint.Y != e.Y) {
                    if (this.moveTabFrom != null) {
                        base.DoDragDrop(moveTabFrom, DragDropEffects.Move);
                    }
                }
            }
        }

        /// <summary>
        /// OnMouseUp
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e) {
            base.OnMouseUp(e);
            Point pt = new Point(e.X, e.Y);
            if (e.Button == MouseButtons.Right) {
                this.SelectedTab = this.GetTabFromPoint(pt);
            }
            this.mouseClickPoint = Point.Empty;
            this.moveTabFrom = null;
        }

        /// <summary>
        /// GetTabFromPoint
        /// </summary>
        /// <param name="pt"></param>
        /// <returns></returns>
        public TabPage GetTabFromPoint(Point pt) {
            for (int i = 0; i < this.TabCount; i++) {
                if (base.GetTabRect(i).Contains(pt)) {
                    return base.TabPages[i];
                }
            }
            return null;
        }

        /// <summary>
        /// IndexOfTab
        /// </summary>
        /// <param name="tabPage"></param>
        /// <returns></returns>
        public int IndexOfTab(TabPage tabPage) {
            for (int i = 0; i < this.TabCount; i++) {
                if (base.TabPages[i] == tabPage) {
                    return i;
                }
            }
            return -1;
        }
    }
}

コメント

タイトルとURLをコピーしました