1

I'm trying to create a tabbed notepad application but having problems in deleting the "close buttons" on the tabs. The tabs gets removed as they should, but I'm only able to remove 1 close button. Can anyone please help and direct me into the right direction:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace My_Notepad
{
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }


    int TabCount = 0;
    int btx = 96;
    private int i;

    public void newBox()
    {

        TabPage tp = new TabPage("New Document          ");
        RichTextBox rtb = new RichTextBox();
        rtb.Dock = DockStyle.Fill;
        tp.Controls.Add(rtb);
        tabControl1.TabPages.Add(tp);
        this.tabControl1.SelectedTab = tp;
        this.tabControl1.Appearance = TabAppearance.FlatButtons;


        Button btnPlay = new Button();
        this.btnPlay = btnPlay;

        btnPlay.Width = 16;
        btnPlay.Height = 18;
        btnPlay.FlatStyle = FlatStyle.Flat;
        btnPlay.FlatAppearance.BorderSize = 0;
        btnPlay.Top = 25;
        btnPlay.Left = btx;
        btnPlay.Image = Image.FromFile(@"C:\\close-button.png");
        btnPlay.Click += new EventHandler(btnPlay_Click);
        this.Controls.Add(btnPlay);
        btnPlay.BringToFront();
        TabCount++;
        i++;

    }



    private void btnPlay_Click(object sender, EventArgs e)
    {

        tabControl1.SelectedTab.Dispose();
        this.Controls.Remove(btnPlay);

    }


    private void newToolStripMenuItem_Click(object sender, EventArgs e)
    {
        newBox();

        btx = btx + 126;
    }



    public Button btnPlay { get; set; }


   }
   }
TaW
  • 53,122
  • 8
  • 69
  • 111

1 Answers1

1

Your problem seems to be, that you don't keep separate references to the Buttons you create. The way you wrote the code, suggests that you have a class level variable btnPlay, to which you assign a dynamically created local variable btnPlay, thereby overwriting the reference to the old Button:

Button btnPlay = new Button();
this.btnPlay = btnPlay;

Later, when you try to delete the Buttons, you can only reach the last one.

To avoid this you need to keep references that connect each Button to the TabPage it refers to. The most common way is to use the Tag of your pages to hold a reference:

Button btnPlay = new Button();
this.btnPlay = btnPlay;  
tp.Tag = btnPlay;

Now you can reach it as long as the TabPage is still alive:

private void btnPlay_Click(object sender, EventArgs e)
{
    Button btnPlay = ((sender as TabPage).Tag as Button);
    ..
}

However, since all you want to do is get rid of it, there is an even simpler solution: In the btnPlay_Click event you have a reference to the correct Button via the sender param..:

private void btnPlay_Click(object sender, EventArgs e)
{
    tabControl1.SelectedTab.Dispose();
    (sender as Button).Dispose();
}

For this you don't even need to use the Tag.. Not sure if you do anything with the class level btnPlay..??

However..

..the way I read it, your code has one more problem: Each close button only closes the currently selected TabPage instead of the one it belongs to.. So what we actually need, is to keep a reference from each Button to its TabPage, not the other way round..:

Button btnPlay = new Button();
this.btnPlay = btnPlay;  // what is it good for?
btnPlay.Tag = tp;

Now this should work:

private void btnPlay_Click(object sender, EventArgs e)
{
    Button btnPlay = sender as Button;
    (btnPlay.Tag as TabPage).Dispose();
    btnPlay.Dispose();
}

Btw, if you are otherwise happy with your solution, by all means stick to it! Just wanted to mention, that usually one uses owner drawing the TabControl to add adornments like close buttons. Your way sounds a little simpler, I'd say, at least until you want to move or resize the Tab..

Update: since you asked about owner-drawing, here is a minimal example:

Rectangle currentCrossRect = Rectangle.Empty;

private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
    Bitmap cross = yourCloseImage;
    int xWidth = cross.Width;
    TabPage tp = tabControl1.TabPages[e.Index];
    e.DrawBackground();
    e.DrawFocusRectangle();
    Size size = tabControl1.ItemSize;
    using (SolidBrush brush = new SolidBrush(e.ForeColor))
        e.Graphics.DrawString(tp.Text, e.Font, brush, e.Bounds.Left + 2 , 5);
    if (tabControl1.SelectedTab == tp)
    {
        currentCrossRect = new Rectangle( 
                           e.Bounds.Left + size.Width - 20, 3, xWidth,xWidth);
        e.Graphics.DrawImage(cross, currentCrossRect.X, currentCrossRect.Y);
    }
}


private void tabControl1_MouseClick(object sender, MouseEventArgs e)
{
    TabPage tp = tabControl1.SelectedTab;

    if (currentCrossRect.Contains(e.Location)) tp.Dispose();
}
TaW
  • 53,122
  • 8
  • 69
  • 111
  • Hi TaW, Thank you very much. I have applied your solution and is working great. I see now what you mean with when resizing and moving tabs - the buttons remains on previous location when closing tabs. I will play around and see if I can get past that, if not, I will have a look at owner drawing. Thanks again - much appreciated – Jaco Hendriks May 22 '15 at 18:47
  • Glad that is works for you. If you feel the question is answered, please consider marking it as accepted. For your further test you may want to have a look at this [post](http://stackoverflow.com/questions/30399467/tab-page-header-location/30401414?noredirect=1#comment48894687_30401414) – TaW May 22 '15 at 18:50
  • Hi TaW, Seems like I need to look at the owner drawing option as I can't get around what I currently have. Do you know of any good tutorials on owner drawing specific to close buttons for tabs? Thanks and regards. – Jaco Hendriks May 23 '15 at 20:23
  • [Here](http://stackoverflow.com/questions/26327942/using-graphics-drawimage-to-create-custom-tabs-in-c-sharp/26328643?s=4|0.1472#26328643) is a solution that shows owner drawing. Note that it actually draws individual glyphs onto the Tabs, not just one 'X', so you should be able to simplify it. BTW: There are two ways to show closing buttons: Firefox sgow it on each page. VStudio only on the active tab. The latter is obviously simpler to get right.. – TaW May 23 '15 at 20:30
  • While it ought to be in a separate question, have added minimal code, using one x on the selected tab only.. – TaW May 23 '15 at 20:50
  • Thank you TaW - you are a star. I have now used your above code and it works perfectly. I have managed to change it a bit so that each tab have an image with a click event. Much appreciated – Jaco Hendriks May 24 '15 at 01:02