[.net] Why is the .NET framework removing my control?

Started by
3 comments, last by Toolmaker 18 years, 9 months ago
I'm having the STRANGEST thing ever. I'm currently working on my own control, and to make things easier, I decided to derive most things from a panel. I'm building a small "toolbar" with buttons on it. If you select the top-button, the control collapses and shows it's child buttons. So, I have a ButtonBar(Main control), a ButtonBand(Holds the top-level button and the a contentpane) and ContentPane(Holds all the other buttons). Well, I create a new ButtonBar, call ButtonBar.AddBand(caption, contentPane) which looks like this:

public void AddBand(string caption, ContentPane pane)
{
	if (pane == null) // Sanity check
		throw new NullReferenceException("ContentPane is null");

    int index = Controls.Count;
    ButtonBand band = new ButtonBand(caption, pane, new BandInfo(this, index));
    RecalcLayout(band, index);

    this.Controls.Add(band);
}
Now, all the code works here. The RecalcLayout works fine(It adjusts the size of the controls). However, after calling Controls.Add(band), it goes nuts. I added a ComponentRemoved eventhandler to the class and it gets triggered. The strangest thing is, I never call Remove() or similar on the control. The framework does it by itself. If you're interested in the complete source(It's not too big):

using System;
using System.Drawing;
using System.Windows.Forms;

namespace Toolmaker
{
    internal class BandInfo
    {
        public ButtonBar buttonBar;
        public int index;

        public BandInfo(ButtonBar parent, int ind)
        {
            buttonBar = parent;
            index = ind;
        }
    }

	/// <summary>
	/// Summary description for ButtonBar.
	/// </summary>
	public class ButtonBar : System.Windows.Forms.Panel
	{
        private int buttonHeight;
		private int selection = -1;
		public ButtonBar()
		{
            buttonHeight = 25;
		}

        public void AddBand(string caption, ContentPane pane)
        {
			if (pane == null)
				throw new NullReferenceException("ContentPane is null");

            int index = Controls.Count;
            ButtonBand band = new ButtonBand(caption, pane, new BandInfo(this, index));
            RecalcLayout(band, index);

            this.Controls.Add(band);
        }

        private void RecalcLayout(ButtonBand band, int index)
        {
			int posX = 0;
			int height = buttonHeight;
			if (index >= 1)
				posX = Controls[index - 1].Location.Y + Controls[index - 1].ClientSize.Height;

            // Set size/location of the band
            band.Size = new Size(this.ClientSize.Width, band.CalcHeight());
            band.Location = new Point(0, posX);

            // Set the size/location of the top button
            band.Controls[0].Size = new Size(band.ClientSize.Width, buttonHeight);
            band.Controls[0].Location = new Point(0, 0);

			if (index == selection)
				height = band.Controls[1].Controls.Count * buttonHeight;
            band.Controls[1].Size = new Size(band.ClientSize.Width - 10, height);
            band.Controls[1].Location = new Point(ClientRectangle.Width, 0);
        }

		private void RedrawBands()
		{
			for (int index = 0; index < this.Controls.Count; ++index)
			{
				string st = Controls[index].Text;

				ButtonBand band = this.Controls[index] as ButtonBand;
				int y = band.Controls[0].Controls.Count;
				int i = band.Controls.Count;
				RecalcLayout(band, index);
			}
		}

		public void SelectBand(int selection)
		{
			this.selection = selection;
			RedrawBands();
		}
	}

    internal class ButtonBand : System.Windows.Forms.Panel
    {
        BandInfo info = null;
		ContentPane contentPane = null;

        public ButtonBand(string caption, ContentPane pane, BandInfo info)
        {
            this.info = info;
			this.contentPane = pane;

            Button btn = new Button();
            btn.Text = caption;
            Controls.Add(btn);
			Controls.Add(contentPane);

            btn.Click += new EventHandler(OnClick);
			this.ControlRemoved += new ControlEventHandler(OnControlRemoved);
        }

		public int CalcHeight()
		{
			return (25 + contentPane.Controls.Count * 25);
		}

		private void OnControlRemoved(object sender, ControlEventArgs e)
		{
			//MessageBox.Show(this, "Control removed from band");
		}

		private void OnClick(object sender, EventArgs e)
        {
			info.buttonBar.SelectBand(info.index);
        }
    }
    
    public class ContentPane : System.Windows.Forms.Panel
    {
        public ContentPane()
        {
        }

        public void AddButton(string caption, EventHandler eventHandler)
        {
            Button btn = new Button();
            btn.Text = caption;

            btn.Size = new Size(this.ClientSize.Width, 25);
            btn.Location = new Point(10, Controls.Count * 25);

            Controls.Add(btn);
        }

        public int CalculateSize()
        {
            return (Controls.Count * 25);
        }
    }
}

Ideas on this? Toolmaker

Advertisement
To reproduce the problem, I just have to put a ButtonBar on a Form and add this line, right?
this.buttonBar1.AddBand("test", new Toolmaker.ContentPane());
That works fine here..
This is my test application:

            buttonBar = new Toolmaker.ButtonBar();            buttonBar.Location = new Point(0, 0);            buttonBar.Size = new Size(200, this.ClientSize.Height);            buttonBar.Borderstyle = Borderstyle.FixedSingle;            Controls.Add(buttonBar);			Toolmaker.ContentPane pane = new Toolmaker.ContentPane();			pane.AddButton("Artikelen", new EventHandler(OnClick));			pane.AddButton("Barcodes", new EventHandler(OnClick));			pane.AddButton("Aanbiedingen", new EventHandler(OnClick));            buttonBar.AddBand("Artikelbeheer", pane);            buttonBar.AddBand("Kassa verwerking", pane);			buttonBar.AddBand("Medewerkers", pane);


Ignore the dutch.

Toolmaker

You are calling buttonBar.AddBand three times in a row, and pass in the same pane-object. In the ButtonBand constructor, you add the pane to the ButtonBar.Controls-collection. The first time this happens, pane.Parent == null. The second time however, pane already has its Parent set, and in order to add to the new ButtonBar's Controls, it is first removed from its current parent (the other ButtonBar)..
Quote:Original post by itachi
You are calling buttonBar.AddBand three times in a row, and pass in the same pane-object. In the ButtonBand constructor, you add the pane to the ButtonBar.Controls-collection. The first time this happens, pane.Parent == null. The second time however, pane already has its Parent set, and in order to add to the new ButtonBar's Controls, it is first removed from its current parent (the other ButtonBar)..


Thank you, that did the job! ++Rating for you sir!

Toolmaker

This topic is closed to new replies.

Advertisement