AnisTabControlを少し改造
AnisTabControlを少し改造。
派生してもよかったけど、別途作成。
なお、原典は以下のURLです。
http://www.k4.dion.ne.jp/~anis7742/codevault/00070.html
なお、改造がへたれなことは、すみませぬ。
AnisTabControlでは、タブ札ドラッグ&ドロップする際、属するTabPageをリフレクションを使って以下のように取得していた。
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; } }
これだと、typeof(TabPage)はコンパイル時に静的に値がセットされ、かつTabPageのサブクラスを指定できない。
この影響で、AnisTabControlにTabPageのサブクラスをAddメソッドでセットすると、そのサブクラスのタブ札はドラッグもドロップもできなくなる。
そこで、リフレクションを使っている部分を以下のように置き換えた。
void AnisTabControl_DragEnter(object sender, DragEventArgs e) { //Type myType = e.Data.GetType(); TabPage myTabPage = e.Data.GetData(this.GetThisTabPageType(), true) as TabPage; if (myTabPage != null && this.TabPages.Contains(myTabPage) && this.TabIndexFromPoint(this.PointToClient(new Point(e.X, e.Y))) != -1) { e.Effect = DragDropEffects.Move; } else { e.Effect = DragDropEffects.None; } }
ここでの、
this.GetThisTabPageType()
は、protectedなvirtualメソッドで以下のように、タイプの文字列を返す。
protected virtual string GetThisTabPageType() { return "System.Windows.Forms.TabPage"; }
この文字列をリフレクションでTabPageのインスタンスを取得する際のGetDataに使用する。
これを、KAnisTabControlのサブクラスで、たとえば、
public class MyAnisTabControl : KAnisTabControl { protected override string GetThisTabPageType() { return "ABCS.Classes.MyTabPage"; }
のように替えると、MyTabPageがドラッグ&ドロップの対象になる。
やっているのは単にこれだけ。
他のTabPageのサブクラスはドラッグ&ドロップの対象にならないというおまけつき。( ̄Д ̄;;
リフレクションはよくわからない。。。
GetDataの対象がTabPageのサブクラス全部になったら、こんなことしないでいいのに。
KAnisTabControlのソースは以下。
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Drawing; using System.ComponentModel; namespace ABCS.Classes { ///TabMouseClickイベントを処理するメソッドを表します。 public delegate void TabMouseEventHandler(object sender, TabMouseEventArgs e); ///タブ部分がクリックされた際に、 /// クリックされたタブを取得出来るTabMouseClickイベントを備えたTabControl public class KAnisTabControl : TabControl { //リフレクションでデータ取得用する型名(string)を取得。 //子クラスでオーバーライドすること。 //(テンプレートメソッド) protected virtual string GetThisTabPageType() { return "System.Windows.Forms.TabPage"; } #region//各種TabMouseEvent定義 ///クリックされたタブが取得可能なMouseDownイベント [Category("アクション"), Description("マウスでタブをクリックした時に発生します。")] public event TabMouseEventHandler TabMouseDown; ///クリックされたタブが取得可能なMouseClickイベント [Category("アクション"), Description("マウスでタブをクリックした時に発生します。")] public event TabMouseEventHandler TabMouseClick; ///クリックされたタブが取得可能なMouseUpイベント [Category("アクション"), Description("マウスでタブをクリックした時に発生します。")] public event TabMouseEventHandler TabMouseUp; ///クリックされたタブが取得可能なMouseDoubleClickイベント [Category("アクション"), Description("マウスでタブをダブルクリックした時に発生します。")] public event TabMouseEventHandler TabMouseDoubleClick; ///クリックされたタブが取得可能なMouseWheelイベント [Category("アクション"), Description("マウスホイールがタブ上で動かされた時に発生します。")] public event TabMouseEventHandler TabMouseWheel; ///クリックされたタブが取得可能なMouseMoveイベント [Category("アクション"), Description("マウスポインタがコントロール上を移動すると発生します。")] public event TabMouseEventHandler TabMouseMove; #endregion ///XMLコメントが無いって警告うざい public KAnisTabControl() { #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 } ///Point上のタブコントロールのタブ部分に対応したTabPageのインデックスを取得 /// インデックスを取得するPoint ///Point上にタブが無ければ-1が返ります。。 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; ///trueでドラッグ&ドロップによるタブの並び替えを可能にします。 [Category("動作"), Description("trueでドラッグ&ドロップによるタブの並び替えを可能にします。")] public bool SortTabDragDrop { set { if (sortTabDragDrop == value) return; 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) { //Type myType = e.Data.GetType(); TabPage myTabPage = e.Data.GetData(this.GetThisTabPageType(), true) as TabPage; if (myTabPage != null && this.TabPages.Contains(myTabPage) && 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))); //Type myTabType = e.Data.GetType(); TabPage tabPage = e.Data.GetData(this.GetThisTabPageType(), true) as TabPage; if (tabPage != null) { this.TabPages.Remove(tabPage); this.TabPages.Insert(index, tabPage); this.SelectTab(index); } } #endregion } ///TabMouseClickイベントのデータ public class TabMouseEventArgs : MouseEventArgs { private int tabIndex_; /// クリックされたタブに対応したタブのインデックス public TabMouseEventArgs(int tabIndex, MouseButtons button, int clicks, int x, int y, int delta) : base(button, clicks, x, y, delta) { tabIndex_ = tabIndex; } ///クリックされたタブに対応したタブページ public int TabIndex { get { return tabIndex_; } } } }
ちなみに、TabPageのサブクラスは以下のものを使っています。
using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; namespace ABCS.Classes { public class MyTabPageWithWeb : TabPage { private MyWebBrowser web_ = null; private MyTabControlWidthRadio childTabControl_ = null; public MyWebBrowser ChildWebBrowser { get { return this.web_; } } public MyTabControlWidthRadio ChildTabControlWithRadio { get { return this.childTabControl_; } } public MyTabPageWithWeb(Form parentForm, string url) : base() { //this.AllowDrop = true; this.web_ = new MyWebBrowser(parentForm, this, 10); this.childTabControl_ = new MyTabControlWidthRadio(); /* //①Dock は後続の方が優先される(スタック形式?) ctabctrl.Dock = DockStyle.Top; tab.Controls.Add(ctabctrl); */ //Web表示 this.web_.Dock = DockStyle.Fill; this.Controls.Add(this.web_); // //②Dock は後続の方が優先される(スタック形式?) // //そのため、ctabctrlのaddをwebのaddより後方に移した。 // //(①を②に移した) this.childTabControl_.Dock = DockStyle.Top; this.Controls.Add(this.childTabControl_); //web.DocumentCompleted += webDocumentCompleted; this.web_.Navigate(url); } } }