C#|TabControlのタブをドラッグ&ドロップで並び替え

 C#|TabControlでクリックされたタブが判らないのコードを手直ししました。デザイナー上でタブを切り替えると怒られるというどうしようもない失敗です。原因が良くわからなかったのでtry-catchで無理やり直しました。(こんなんでいいのか?)

 ついでにClickイベントだけじゃ物足りないと思ったのでコピペ&力技でイベントを増設しました。偉い人はもっとスマートに書けるのでしょうか?

 そして本題です。ついでにタブのD&Dに対応しちゃえ!って思ったのです。それ自体は簡単に出来ました。しかし、そこから苦労しました。と言うのも、タブが切り替わるタイミングがボタンを押して離した時ではなくて、ボタンを押し下げた瞬間なんです。つまり、ドラッグするとそのタブが選択されてしまうのです。そしてそのままドロップすると、移動したタブではなくて一番左のタブが選択されているのです。

 僕が望んだ仕様は、選択されていないタブを選択しないまま並び替えられるというものです。せめてドラッグしたときはそのタブが選択されても、ドロップが終わったときには元のタブに戻るようにしようと思いました。そこで選択されたタブの履歴を取って、そこから戻すようにしてみました。でも、選択されているタブをD&Dしたら全く関係ないタブが選択されています。

 色々試しましたが、制御仕切れなかったので諦めました。D&Dしたタブを選択するようにしました。

 ちょっと長いけど晒します。どなたか添削してくれると嬉すぃです…。

using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace Anis.Controls {
  /// <summary>TabMouseClickイベントを処理するメソッドを表します。</summary>
  public delegate void TabMouseEventHandler(object sender, TabMouseEventArgs e);
  /// <summary>タブ部分がクリックされた際に、
  /// クリックされたタブを取得出来るTabMouseClickイベントを備えたTabControl</summary>
  public class AnisTabControl: TabControl {
    #region//各種TabMouseEvent定義
    /// <summary>クリックされたタブが取得可能なMouseDownイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseDown;
    /// <summary>クリックされたタブが取得可能なMouseClickイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseClick;
    /// <summary>クリックされたタブが取得可能なMouseUpイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseUp;
    /// <summary>クリックされたタブが取得可能なMouseDoubleClickイベント</summary>
    [Category("アクション"),
    Description("マウスでタブをダブルクリックした時に発生します。")]
    public event TabMouseEventHandler TabMouseDoubleClick;
    /// <summary>クリックされたタブが取得可能なMouseWheelイベント</summary>
    [Category("アクション"),
    Description("マウスホイールがタブ上で動かされた時に発生します。")]
    public event TabMouseEventHandler TabMouseWheel;
    /// <summary>クリックされたタブが取得可能なMouseMoveイベント</summary>
    [Category("アクション"),
    Description("マウスポインタがコントロール上を移動すると発生します。")]
    public event TabMouseEventHandler TabMouseMove;
    #endregion
    /// <summary>XMLコメントが無いって警告うざい</summary>
    public AnisTabControl() {
      #region//TabMouseEvent関連イベント登録
      this.MouseDown += new MouseEventHandler(AnisTabControl_MouseDown);
      this.MouseClick += new MouseEventHandler(AnisTabControl_MouseClick);
      this.MouseUp += new MouseEventHandler(AnisTabControl_MouseUp);
      this.MouseDoubleClick += new MouseEventHandler(AnisTabControl_MouseDoubleClick);
      this.MouseWheel += new MouseEventHandler(AnisTabControl_MouseWheel);
      this.MouseMove += new MouseEventHandler(AnisTabControl_MouseMove);
      #endregion
    }
    /// <summary>Point上のタブコントロールの
    ///タブ部分に対応したTabPageのインデックスを取得</summary>
    /// <param name="point">インデックスを取得するPoint</param>
    /// <returns>Point上にタブが無ければ-1が返ります。。</returns>
    private int TabIndexFromPoint(Point point) {
      for(int i = 0; i <= this.TabPages.Count - 1; i++) {
        if(this.GetTabRect(i).Contains(point)) {
          return i;
        }
      }
      return -1;
    }
    #region//Tabマウスイベント
    void AnisTabControl_MouseDown(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseDown(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseClick(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseClick(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseUp(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseUp(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseDoubleClick(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseDoubleClick(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseWheel(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseWheel(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    void AnisTabControl_MouseMove(object sender, MouseEventArgs e) {
      try {
        int index = TabIndexFromPoint(e.Location);
        if(index != -1) {
          TabMouseEventArgs E = new TabMouseEventArgs(
          	index, e.Button, e.Clicks, e.X, e.Y, e.Delta);
          this.TabMouseMove(sender, E);
        }
      } catch(NullReferenceException) {}
    }
    #endregion
    #region//ドラッグ&ドロップ
    Point mouseDownPoint = Point.Empty;
    bool sortTabDragDrop;
    /// <summary>trueでドラッグ&ドロップによるタブの
    ///並び替えを可能にします。</summary>
    [Category("動作"),
    Description("trueでドラッグ&ドロップによるタブの並び替えを可能にします。")]
    public bool SortTabDragDrop {
      set {
        sortTabDragDrop = value;
        if(value) {
          this.MouseDown += new MouseEventHandler(AnisTabControl_MouseDown1);
          this.MouseUp += new MouseEventHandler(AnisTabControl_MouseUp1);
          this.TabMouseMove += new TabMouseEventHandler(AnisTabControl_TabMouseMove);
          this.DragEnter += new DragEventHandler(AnisTabControl_DragEnter);
          this.DragOver += new DragEventHandler(AnisTabControl_DragOver);
          this.DragDrop += new DragEventHandler(AnisTabControl_DragDrop);
        } else {
          this.MouseDown -= new MouseEventHandler(AnisTabControl_MouseDown1);
          this.MouseUp -= new MouseEventHandler(AnisTabControl_MouseUp1);
          this.TabMouseMove -= new TabMouseEventHandler(AnisTabControl_TabMouseMove);
          this.DragEnter -= new DragEventHandler(AnisTabControl_DragEnter);
          this.DragOver -= new DragEventHandler(AnisTabControl_DragOver);
          this.DragDrop -= new DragEventHandler(AnisTabControl_DragDrop);
        }
      }
      get {
        return sortTabDragDrop;
      }
    }
    void AnisTabControl_MouseDown1(object sender, MouseEventArgs e) {
      if(e.Button == MouseButtons.Left) {
        mouseDownPoint = e.Location;
      } else {
        mouseDownPoint = Point.Empty;
      }
    }
    void AnisTabControl_MouseUp1(object sender, MouseEventArgs e) {
      mouseDownPoint = Point.Empty;
    }
    void AnisTabControl_TabMouseMove(object sender, TabMouseEventArgs e) {
      if(mouseDownPoint != Point.Empty) {
        Rectangle mouseMoveRectangle = new Rectangle(
          mouseDownPoint.X - 5, mouseDownPoint.Y - 5,
          10, 10);
        if(!mouseMoveRectangle.Contains(e.Location)){
          this.DoDragDrop(this.TabPages[e.TabIndex], DragDropEffects.Move);
        }
      }
    }
    void AnisTabControl_DragOver(object sender, DragEventArgs e) {
      mouseDownPoint = Point.Empty;
    }
    void AnisTabControl_DragEnter(object sender, DragEventArgs e) {
      if(e.Data.GetDataPresent(typeof(TabPage)) &&
        this.TabPages.Contains((TabPage)(e.Data.GetData(typeof(TabPage)))) &&
        this.TabIndexFromPoint(this.PointToClient(new Point(e.X,e.Y))) != -1){
        e.Effect = DragDropEffects.Move;
      } else {
        e.Effect = DragDropEffects.None;
      }
    }
    void AnisTabControl_DragDrop(object sender, DragEventArgs e) {
      int index = TabIndexFromPoint(this.PointToClient(new Point(e.X,e.Y)));
      TabPage tabPage = (TabPage)(e.Data.GetData(typeof(TabPage)));
      this.TabPages.Remove(tabPage);
      this.TabPages.Insert(index, tabPage);
      this.SelectTab(index);
    }
    #endregion
  }
  /// <summary>TabMouseClickイベントのデータ</summary>
  public class TabMouseEventArgs:MouseEventArgs {
    private int tabIndex_;
    /// <param name="tabIndex">クリックされたタブに対応したタブのインデックス</param>
    public TabMouseEventArgs(
    	int tabIndex,MouseButtons button,int clicks, int x, int y ,int delta):base(
    		button,clicks,x,y,delta) {
      tabIndex_ = tabIndex;
    }
    /// <summary>クリックされたタブに対応したタブページ</summary>
    public int TabIndex {
      get {
        return tabIndex_;
      }
    }
  }
}

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください