Search code examples
c#headertabpagemenustripclose-button

Tabpage that opens by menustrip button, but closes by the image on the tabpage header


I have the main form where there's tabcontrol and menustrip. In menustrip there are few buttons that should open the tabpages in tabcontrol with defined name and the perspective to fill in it with own content. But the function of closing the tabpage should be also present. My idea is not usage of distinct button, but a usage of special button on the tabpage header. Obviously, it would be some picture with cross imaged on it.

I used the property of tabcontrol DrawMode=OwnerDrawFixed. There's no picture in the header of tabpage in spite of the directory and name of file are correct. It is situated in the folder wherein exe file exists. Also there's no label in the header whilst the width of header witnesses that the text is present but invisible.

public partial class Core : Form
{
    private string closeButtonFullPath = "button-close.png";

    public Core()
    {
        InitializeComponent();
    }

     //  Do not forget this namespace or else DllImport won't work       
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wp, IntPtr lp);
    private const int TCM_SETMINTABWIDTH = 0x1300 + 49;
    private void tabControl1_HandleCreated(object sender, EventArgs e)
    {
        SendMessage(this.tabControl1.Handle, TCM_SETMINTABWIDTH, IntPtr.Zero, (IntPtr)16);
    }

    private void tabControl_DrawItem(object sender, DrawItemEventArgs e)
    {
        try
        {
            var tabPage = this.tabControl1.TabPages[e.Index];
            var tabRect = this.tabControl1.GetTabRect(e.Index);
            tabRect.Inflate(-2, -2);
            var closeImage = new Bitmap(closeButtonFullPath);
            e.Graphics.DrawImage(closeImage,
                (tabRect.Right - closeImage.Width),
                tabRect.Top + (tabRect.Height - closeImage.Height) / 2);
            TextRenderer.DrawText(e.Graphics, tabPage.Text, tabPage.Font,
                tabRect, tabPage.ForeColor, TextFormatFlags.Left);
        }
        catch (Exception ex) { throw new Exception(ex.Message); }
    }

    private void списокПерсонToolStripMenuItem_Click(object sender, EventArgs e)
    {
        string texttab = "Список персон";

        TabPage ListPersons = new TabPage(texttab);
        tabControl1.TabPages.Add(ListPersons);
    }

    private void списокОрганізаційToolStripMenuItem_Click(object sender, EventArgs e)
    {
        TabPage tp = new TabPage();
        tp.Name = "Tab_OrganizationList";
        tabControl1.TabPages.Add(tp);
    }

    private void tabControl1_MouseDown(object sender, MouseEventArgs e)
    {
        for (var i = 0; i < this.tabControl1.TabPages.Count - 1; i++)
        {
            var tabRect = this.tabControl1.GetTabRect(i);
            tabRect.Inflate(-2, -2);
            var closeImage = new Bitmap(closeButtonFullPath);
            var imageRect = new Rectangle(
                (tabRect.Right - closeImage.Width),
                tabRect.Top + (tabRect.Height - closeImage.Height) / 2,
                closeImage.Width,
                closeImage.Height);
            if (imageRect.Contains(e.Location))
            {
                this.tabControl1.TabPages.RemoveAt(i);
                break;
            }
        }
    }
}

Solution

  • What you are describing is not TabPage functionality, but Window Docking / MDI.

    Where each Document (Page) is actually a separate form instance which can be closed, hidden, etc.

    This is a guide for simple MDI window creation https://www.c-sharpcorner.com/UploadFile/84c85b/building-mdi-winforms-application-using-C-Sharp/

    If you want docking and more advance features then you need to use a 3PP library. I suggest to check these out:

    https://github.com/dockpanelsuite/dockpanelsuite

    https://github.com/ComponentFactory/Krypton