Pull to refresh

Создание собственного контрола на основе TabControl в C#

Reading time 4 min
Views 44K


В один момент возникла задача сделать TabControl по отрисованному дизайну, с вкладками с левой стороны. Сложность была в том, что проект был уже написан с использованием winform, и переделывать его целиком не хотелось. Попытался реализовать эту задачу средствами класического TabControl, но встретился со множеством проблем, связанных с этим.

Первой проблемой стало то, что если спозиционировать вкладки с левой стороны, то мы получаем следующую картину:



Но мне нужно было, чтобы надписи шли гаризонтально. Изучив чуть глубже данный контрол, решил воспользоваться параметром DrawMode=OwnerDrawFixed. Все надписи стерлись, и на кнопке стало возможным писать и рисовать. Но остался фон самой кнопки, который полностью закрасить не удалось.
Следующим шагом поменял Appearance c Normal на Buttons, был еще вариант FlatButtons, но через конструктор его поставить не удалось, а выставление в коде ни на что не повлияло.
В режиме Buttons вылезла такая ерунда:



На картинке видно, что между кнопками и набором TabPages появилось расстояние. Отуда оно взялось и каким параметром регулируется, мне выяснить так и не удалось.

Еще некоторое время я изучал существующие платные и бесплатные библиотеки контролов на наличие возможности изменения под себя вкладок TabControl, но они либо предлагали использовать заранее созданные стили, либо позволяли максимум поменять цвет.

В итоге намучившись с ним, я решил написать свой контрол, взяв за основу стандартный. Целью стало скрыть стандартные вкладки и на смену им поставить свои, завязав их на контрол.

Постараюсь подробно описать все, что для этого пришлось сделать.

Шаг 1
Для начала в проекте нужно создать новый котрол. Для этого в панели Solution Explorer кликаем правой кнопкой по проекту, далее Add->Component, в открывшейся панели вводим имя нового контрола (у меня это NewTabControl)

Шаг 2
После создания открываем код созданного контрола. В коде делаем следующие правки:
дописываем
using System.Windows.Forms;
using System.Drawing;

Создаем три класса, наследуя их от классов стандартных контролов.

Класс нового TabControl
public partial class NewTabControl: System.Windows.Forms.TabControl

Класс нового контрола
public class NewTabPanel: System.Windows.Forms.Panel

Класс одной вкладки
public class PanelTP: System.Windows.Forms.Panel

Теперь нам нужно перезагрузить следующий метод в классе NewTabControl:
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == 0x1328 && !DesignMode) m.Result = (IntPtr)1;
            else base.WndProc(ref m);
        }
        

Данное действие позволит нам скрыть стандартные вкладки.

Теперь нам нужно связать все классы между собой. Не буду описывать весь код, его я приложу к данной статье. Опишу только самые интересные моменты.

Шаг 3
Компонуем все элементы в классе NewTabPanel:
        private void InitializeComponent()
        {
            this.panel2 = new System.Windows.Forms.Panel(); //Панель с вкладками
            this.tabControl = new NewTabControl(); 
            this.Controls.Add(this.tabControl);
            this.Controls.Add(this.panel2);            
            this.Size = new System.Drawing.Size(311, 361);
            this.panel2.Dock = System.Windows.Forms.DockStyle.Left;            
            this.tabControl.Dock = System.Windows.Forms.DockStyle.Fill;         
            tabControl.ControlAdded += new ControlEventHandler(tc_ControlAdded); //Событие на создание новой вкладки
            tabControl.ControlRemoved += new ControlEventHandler(tc_ControlRemoved); //Событие удаления вкладки
            tabControl.Selected += new TabControlEventHandler(tc_Selected); //Событие выделения вкладки
        }


Шаг 4
Теперь можно задать формат, как будет выглядеть сама вкладка.
На данном этапе вы можете сами расположить текст, картинку или любой другой элемент на будущей вкладке. А также задать размер и фон самой вкладки.
У себя я вывожу иконку и название вкладки.

В классе PanelTP создаем метод:
        private void InitializeComponent()
        {            
            this.Height = 27;
            this.Width = 128;
            this.BackgroundImage = Tabpanel.Properties.Resources.tab_c_74;
            this.Click += new EventHandler(Select_Item);
            PictureBox Icon;
            Icon = new PictureBox();
            Icon.Width = 25;
            Icon.Height = 26;
            Icon.Left = 3;
            Icon.Top = 5;
            Icon.Image = Tabpanel.Properties.Resources.green_dialbut_611;
            this.Controls.Add(Icon);

            Label lname;
            lname = new Label();
            lname.Width = 95;
            lname.Height = 25;
            lname.Left = 28;
            lname.Top = 5;
            lname.Font = new System.Drawing.Font("Times New Roman", 8f, FontStyle.Regular);
            lname.Text = this.name;
            lname.Click += new EventHandler(Select_Item);            
           this.Controls.Add(lname);  
        }


Шаг 5
Не буду описывать методы, обрабатывающие события, они подробно описаны в приложенном проекте. Перейду к применению.

После того как мы все сохранили, на панели Toolbox появятся новые компоненты


Теперь мы можем его разместить в нашей форме как захотим.
Чтобы добавить вкладку используем:
newTabPanel1.TabPages.Add("TabName");

Чтобы удалить:
newTabPanel1.TabPages.Remove(newTabPanel1.TabPages[id])

Где id — это номер вкадки

При такой реализации TabControl вы всегда сможете настроить сортировку между вкладками или скрыть выбранную вкладку, сделать вкладку любого размера и оформления, сделать панель с вкладками соврачиваемой и разворачиваемой.
По такому же принципу вы можете создать любой свой контрол скомпоновав и запрограммировав его из имеющихся.

Возможно, для кого-то я описал очевидные вещи, но надеюсь, найдутся и те, кому данная статья будет полезна.

Исходники проекта можно скачать тут.
Бинарник тут.

Возможно вам также будет интересна моя статья Как подключить сторонний браузер в приложении на C#
Tags:
Hubs:
+4
Comments 8
Comments Comments 8

Articles