標準コンポーネントを使用すると、多くの歪みを加えることができてうれしいです。
サンプルを使用してテストプロジェクトにリンクします。
カスタムタイプのtabsから始めましょう 。
残念ながら、TabControlはDataGridViewColumnとは異なり、内部変数を使用してネストされた要素のタイプを指定することはできません。 したがって、これはDataGridViewColumnで行われます。
public class CustomDataGridViewColumn : DataGridViewTextBoxColumn { public CustomDataGridViewColumn() { this->CellTemplate = CustomDataGridViewCell; } }
プロジェクトは、Net 4 Fullプロファイルで次のように変更する必要があります。 System.DesignとSystem.Drawing.Designの2つのアセンブリを接続する必要があります。
残念ながら、TabControlでも同じことはできません; TabControl内で宣言された型TabPageCollectionを再定義する必要があります。 したがって、クラス自体と必要なメソッドを宣言してから、順番に分析します。 はい、すぐに警告します-コードを含むファイル内に「using System.Windows.Forms;」という行がなかったため、サンプルコードの標準コンポーネントへのアクセスには、接頭辞「System.Windows.Forms」が付いています。 TabControlとTabPageは、カスタムオーバーライドされた型です。
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.ComponentModel; using System.Drawing.Design; using System.ComponentModel.Design; namespace WindowsFormsApplication1 { public class TabControl : System.Windows.Forms.TabControl { // . public new class TabPageCollection : System.Windows.Forms.TabControl.TabPageCollection { public TabPageCollection(TabControl owner) : base(owner) { } } public TabControl() { } private TabPageCollection mTabCollection = null; // , Editor . [Editor(typeof(TabPageCollectionEditor), typeof(UITypeEditor))] public new System.Windows.Forms.TabControl.TabPageCollection TabPages { get { if (mTabCollection == null) mTabCollection = new TabPageCollection(this); return mTabCollection; } } } // . . public class TabPageCollectionEditor : System.ComponentModel.Design.CollectionEditor { public TabPageCollectionEditor(Type type) : base(type) { } protected override Type CreateCollectionItemType() { return typeof(TabPage); } protected override Type[] CreateNewItemTypes() { return new Type[] { typeof(TabPage) }; } } }
そして、シンプルなTabPage:
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace WindowsFormsApplication1 { public class TabPage : System.Windows.Forms.TabPage { public TabPage() { } } }
ここではすべてが明確だと思います。 次のステップに進みます。
ユーザーごとにタブを追加します。
この機能を提供するために、TabControlには常に「+」というタイトルの追加の空のタブがあります。 クリックすると、タブ追加イベントが生成されます。
まず、TabPageCollectionタイプでは、Clearメソッドをオーバーロードします。タブをクリアするとき、「+」タブを削除する必要はありません。
public override void Clear() { System.Windows.Forms.TabPage page = null; if (this.ContainsKey(TabControl.KeyPageAllowAddName)) page = this[TabControl.KeyPageAllowAddName]; base.Clear(); if (page != null) this.Add(page); }
TabControlコードで、タブの名前「+」を格納する変数を宣言します。
public static string KeyPageAllowAddName = "___page_allow_to_add_name___";
新しい操作モードを有効/無効にできるように、コンポーネントのAllowUserToAddTabプロパティを宣言します。 実際、そのようなタブの存在を確認し、必要に応じて追加/削除するメソッドです。
public TabControl() { this.Enter += new EventHandler((sender, e) => { CheckAllowUserToAddTab(); }); this.Selecting += new System.Windows.Forms.TabControlCancelEventHandler(TabControl_Selecting); } private bool mAllowUserToAddTab = false; [Browsable(true), Description(" . +, OnUserAddedTab."), Category("Action")] public virtual bool AllowUserToAddTab { get { return mAllowUserToAddTab; } set { mAllowUserToAddTab = value; } } void CheckAllowUserToAddTab() { if (mAllowUserToAddTab) { System.Windows.Forms.TabPage page_allow_to_add = TabPages[KeyPageAllowAddName]; if (mAllowUserToAddTab) { if (page_allow_to_add == null) { page_allow_to_add = new TabPage(); page_allow_to_add.Name = KeyPageAllowAddName; page_allow_to_add.Text = "+"; TabPages.Insert(0, page_allow_to_add); } } else { if (page_allow_to_add != null) TabPages.Remove(page_allow_to_add); } } }
タブ追加イベントのデリゲートについて説明します。
public delegate bool TabPageAdding(TabControl control, TabPage page);
タブを追加するためのイベントとメソッド:
public event TabPageAdding PageAdding; void TabControl_Selecting(object sender, System.Windows.Forms.TabControlCancelEventArgs e) { if (TabPages.Count > 0 && e.TabPage.Name == KeyPageAllowAddName) { e.Cancel = true; TabPage page = new TabPage(); if (PageAdding != null) foreach (TabPageAdding _delegate in PageAdding.GetInvocationList()) { try { if (!_delegate.Invoke(this, page)) return; } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } } TabPages.Add(page); } }
追加イベントへのすべてのサブスクライバーのリストがスクロールされ、そのうちの少なくとも1人がFalseを返すと、追加がキャンセルされます。
TabPageCollectionEditorクラスでは、GetItemsメソッドとSetItemsメソッドをオーバーロードする必要があります。 タブの配列をエディターからコンポーネントに、またはその逆に転送するために必要です。「+」タブは除外する必要があります。
protected override object[] GetItems(object editValue) { try { object[] values = base.GetItems(editValue); List<object> values2 = new List<object>(); foreach (var element in values) { if (element.GetType() == typeof(TabPage)) { TabPage tp = (TabPage)element; if (tp.Name == TabControl.KeyPageAllowAddName) continue; } values2.Add(element); } return values2.ToArray(); } catch (Exception ex){System.Windows.Forms.MessageBox.Show(ex.Message);} return base.GetItems(editValue); } protected override object SetItems(object editValue, object[] value) { try { List<object> values2 = new List<object>(); foreach (var element in value) { if (element.GetType() == typeof(TabPage)) { TabPage tp = (TabPage)element; if (tp.Name == TabControl.KeyPageAllowAddName) continue; } values2.Add(element); } return base.SetItems(editValue, values2.ToArray()); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } return base.SetItems(editValue, value); }
次に、別の機会を追加しました:タブの最初のオープンを追跡します(タブが最初に呼び出されたとき、フォームが初期化されました)
ここで、もう1つのイベント、リストとイベントハンドラーSelectedIndexChanged / Enter / Clickが追加されます。
public TabControl() { this.Enter += new EventHandler(TabControl_PageEvent); this.Click += new EventHandler(TabControl_PageEvent); this.SelectedIndexChanged += new EventHandler(TabControl_PageEvent); this.Enter += new EventHandler((sender, e) => { CheckAllowUserToAddTab(); }); this.Selecting += new System.Windows.Forms.TabControlCancelEventHandler(TabControl_Selecting); } .... private Dictionary<System.Windows.Forms.TabPage, bool> mLoaded = new Dictionary<System.Windows.Forms.TabPage, bool>(); public delegate void TabPageLoadedEventHandler(TabControl control, System.Windows.Forms.TabPage page); public event TabPageLoadedEventHandler PageLoad; void TabControl_PageEvent(object sender, EventArgs e) { if (this.SelectedTab != null && !mLoaded.ContainsKey(this.SelectedTab)) { mLoaded.Add(this.SelectedTab, true); if (PageLoad != null) PageLoad(this, this.SelectedTab); } }
もちろん、ここではまだやることがたくさんあります。たとえば、TabPageControlCollectionでは、メソッドをオーバーロードしてタブの数をより正確に決定できます(「+」タブを除外するため)。
残念ながら、コンポーネントのレンダリングメソッドをオーバーロードすることで+タブの機能を実装する方法を見つけられなかったので、曲線の原因を責めないでください。 たとえば、DevExpressをインストールする代わりに、IMHOを使用します。