Customizing a TabControl for the Closing of Individual Tabs - c#

My scenario is the following:
I am working on a winforms application in C# that has a button inside the main page of a tabcontrol that will generate another tabpage each time that it is clicked. Each new tabpage will contain a layout defined by a user control.
My Questions are:
How can I allow the user to then close one of the tabs that were created dynamically at runtime?
How might I go about modifying the tabcontrol itself so that it has a small 'X' in each tab that the user may click on in order to close that particular tab? (Like Firefox has)
How can I expose the SelectedIndex property of the tabcontrol to the user control if I want to close the tab with a button inside the user control instead?

I found this code and was very helpful to me:
private void tabControl_MouseUp(object sender, MouseEventArgs e)
{
// check if the right mouse button was pressed
if(e.Button == MouseButtons.Right)
{
// iterate through all the tab pages
for(int i = 0; i < tabControl1.TabCount; i++)
{
// get their rectangle area and check if it contains the mouse cursor
Rectangle r = tabControl1.GetTabRect(i);
if (r.Contains(e.Location))
{
// show the context menu here
System.Diagnostics.Debug.WriteLine("TabPressed: " + i);
}
}
}
}
TabControl: How To Capture Mouse Right-Click On Tab

I created a derived tab control about one year ago. I am not going to post the source here, because it's about 700 lines long and coded quite messy. Maybe I will find some time to clean the code up and then release it here. For now I will briefly outline the way it is build.
Each tab page has a 'X' icon to the left of the title and the tab pages support reordering by drag and drop and moving them between multiple tab control.
I choose the easy way to get the icon on the tab pages. The tab control has the TabControl.ImageList property and a tab page has a TabPage.ImageIndex property. So I just added three icons to a image list - normal, hover, pressed - and process the mouse events.
With TabControl.GetTabRect() you can test if the mouse is over a specific tab pages and with some math you find if it is over the icon. Then you just need to change the icon depending on the mouse button state and eventually remove the tab page under the mouse if the button was pressed.
The main problem with this solution is, that calculating if the mouse is over the icon requires to know where the icon is painted relative to the tab page and this might change with a new windows version. And the icon is to the left of the title, but that does not look too bad.

I did the following:
on the create (add) TabPage stage, I added a toolStrip
ToolStrip ts = new ToolStrip();
ts.Dock = DockStyle.Top;
ts.RightToLeft = System.Windows.Forms.RightToLeft.Yes;
Then, create the X button and add it to toolstrip
ToolStripButton ToolStripButton = new ToolStripButton("X");
ts.Items.Add(ToolStripButton);
create an event on clicking the X button
ToolStripButton.Click += new EventHandler(ToolStripButton_Click);
add toolstrip to the tabpage
tabControl1.TabPages[curenttabpage].Controls.Add(ts);
now for the ToolStripButton_Click is as follows:
void ToolStripButton_Click(object sender, EventArgs e)
{
ToolStripButton t = (ToolStripButton)(sender);
ToolStrip ts = t.Owner;
TabPage tb = (TabPage)
(ts.Parent);tabControl1.TabPages.Remove(tb);
}
Maybe it is not as you want, but it will work well.

I created a setup that is similar.
Each control that is added to the tab page at runtime is derived from a special base control I created. This base control has a close button (along with some other features such as safe to close flag).
Close tab code I'm using on my base control:
TabPage tabpage = (TabPage)this.Parent;
TabControl tabControl = (TabControl)tabpage.Parent;
tabControl.TabPages.Remove(parent);

I know this is an old thread but I did find this link that will allow you to "hide" tabs in an array and then you can just re-load the tabs you want at run time. I added this more for a place I can easily find it again.

This code might help throgh closing the tab controls with middle mouse click :
private void tabControl1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button != System.Windows.Forms.MouseButtons.Middle)
return;
for (int i = 0; i < MainTabControl.TabPages.Count; i++)
{
if (this.MainTabControl.GetTabRect(i).Contains(e.Location))
{
this.MainTabControl.TabPages.RemoveAt(i);
return;
}
}
}

It´s works!
TabPage tabpage = (TabPage)this.Parent;
TabControl tabControl = (TabControl)tabpage.Parent;
tabControl.TabPages.Remove(tabpage);

Related

How to access the txt info inside a ToolTip from a programmatically created button?

I have problems to access the string inside a programmatically created button. Have a program which reads from a database and shows in a visual form, with buttons, the info of a specific process. Afterwards I want to make available this info with a "click" and show it in a window of the Form.
I create the button (boton1) programmatically, reading registers in a database (the number of buttons created depends of the registers and their values), and in the same step I create a new nutton I create their Tooltip (Tooltip1). So at the end I have a grid of buttons where I can see their tooltips if I haver the mouse over them. What I need is to be able to press these buttons and show in a textbox the info of these specific button's tooltip. The problem is because the boton1 creation is inside a method which creates the grid it's not accesible (I think this is the reason) from a method_click so the button (boton1) or Tooltip1 doesn't exists inside the button_click event, and if I create them it doesn't show when I click the Tooltip1 info but an empty string...
This is my code with the empty string, it doesn't show the info I see in the tooltips but "..." when I "click" on them.
protected void boton1_Click(object sender, EventArgs e)
{
ToolTip Tooltip1 = new ToolTip();
//This Tooltip is already created in other part of the code but without the code "running" don't exist for the button event creation
Button boton1 = sender as Button;
//Same here, already working and the tooltips seems fine but don't exist in the button_click event
//identify which button was clicked and perform necessary actions
String txtTool = tool.GetToolTip(button);
String info = Tooltip1.GetToolTip(boton1);
}

C# winform: Accessing controls in a usercontrol from every tab page

I have a user control and in this control i have a bunch of text boxes and labels. Now I have linked this user control to another form's tab control. Here is the code I am using
TabPage tp = new TabPage();
tp.Controls.Add(TipUserControl);
tp.Text = "Tab "+ tabctrl_Fields.TabCount + 1;
tabctrl_Fields.TabPages.Add(tp);
When I click on a "Add another tab" button, the above code gets executed and a new tab page with the text boxes (similar to Tab 1) is created.
Now what I am looking for is When the user click on "Done" button in the form (not in the user control), it should be able to loop through every tab and every control (textboxes, labels etc) within that tab. Can anyone suggest on how to write this code?
Thanks in advance,
Swamy
I would add a Tag to the controls that you are searching for and use that approach:
Ability to find WinForm control via the Tag property
private void FindTag(Control.ControlCollection controls)
{
foreach (Control c in controls)
{
if (c.Tag != null)
//logic
if (c.HasChildren)
FindTag(c.Controls); //Recursively check all children controls as well; ie groupboxes or tabpages
}
}
Or iterate recursively over the Tab controls

How to move controls from one tab to another in C# winform program?

I have a C# winform program that has many tabs, and I want to move controls between tabs. and code as below:
private void OnTabControlTabSelected(object sender , EventArgs e)
{
TabPage page = (sender as TabControl).SelectedTab;
foreach(Control control in mLastSelectedTab.Controls)
{
this.mLastSelectedTab.Controls.Remove(control);
page.Controls.Add(control);
}
}
I remove the control from the last selected tab and add it to the new selected tab, but the result is that some controls are added successfully, some are not, I set a breakpoint in this code, and found that the foreach loop doesn't loop through every control in the last selected tab. please help me to solve this problem, thank you!

How to get system tray functionality WITHOUT using NotifyIcon.ContextMenu?

I'm trying to get my application to display a popup context menu when a user right-clicks on my notify icon in the system tray... but there's a twist.
I'm aware that the NotifyIcon class I'm using to get the icon in the system tray has a ContextMenu property. I don't want to use that to get a right-click popup menu, because it ALWAYS displays a right-click popup menu, and never does anything else. When my main form is displaying a modal dialog, I want right-click to activate the main form, NOT display a popup menu.
So, I'm guessing I need to use the NotifyIcon.MouseClick event, and manually pop up the menu in that event? Here's where I've got to so far:
private NotifyIcon trayIcon;
private ContextMenu iconMenu;
private void frmMain_Load(object sender, EventArgs e) {
// [...]
this.trayIcon.MouseClick += new MouseEventHandler(trayIcon_MouseClick);
iconMenu = new ContextMenu();
// [...]
}
private void trayIcon_MouseClick(object sender, MouseEventArgs ea) {
this.iconMenu.Show(Program.instanceFrmMain, new Point(System.Windows.Forms.Cursor.Position.X - Program.instanceFrmMain.Left, System.Windows.Forms.Cursor.Position.Y - Program.instanceFrmMain.Top));
}
Notice how in iconMenu.Show, because it takes popup co-ordinates relative to the parent control (my main form here), I'm annoyingly having to subtract the parent control's co-ordinates from popup co-ordinates, something I already don't want to have to do.
Apart from that, here are the problems I'm having:
Although the menu does popup on right-click, it doesn't close if I click somewhere else on the screen outside the menu - and it should.
The menu doesn't quite popup in the right location; for other system tray apps, it pops up so its bottom-right or bottom-left corner are at the tip of the mouse cursor. For mine, the popup menu is at the base of the screen, to the side of the mouse cursor.
Any ideas how I can get this to work better? I know it's possible, plenty of other apps manually handle the displaying of a popup menu manually instead of using some NotifyIcon.ContextMenu property.
Use the ContextMenuStrip property rather than ContextMenu. The ContextMenuStrip class has an Opening event, which you can cancel by setting e.Cancel = true. That way you don't have to worry about the location of the menu, since it is automatically handled
OK, well I didn't manage to get the functionality I wanted as I described in the original question, but I have managed to find a way to achieve the desired effect using a different method.
I DO attach a ContextMenu to the trayIcon.ContextMenu property, but I attach event handler code to the Popup property of the context menu itself. If, in that handler, I .Clear the ContextMenu, it actually doesn't appear at all, allowing my code to elect to effectively stop the trayicon's popup menu from showing if it wants to. This was the effect I was looking to achieve. If I populate the ContextMenu in the Popup event handler code instead, the menu pops up as usual containing what I populated it with.
Sooo, I managed to solve the problem a different way. :-)

Adding controls to User Controls dynamically

I want to add a control to a user control in an event handler (like a button click event).
I'm trying to add a datagridview lookup control dynamically, but I couldn't get that to work, so I tried just adding a button with this code:
private void btnCreateNewButton_Click(object sender, EventArgs e)
{
Button btn = new Button();
btn.Location = new Point(100, 640);
btn.Size = new Size(100, 30);
btn.Text = "Click Me";
btn.Click += (s, ea) => MessageBox.Show("New button clicked");
this.Controls.Add(btn);
}
When i click my Create New Button, no button appears.
If I add the exact same code into a form instead of a usercontrol, the button is created and displays as intended, but in a user control nothing happens.
In the user control I've also tried
this.Parent.Controls.Add(btn) and
this.ParentForm.Controls.Add(btn)
but to no avail.
Anybody got any ideas?
Thanks,
Ciaran.
You place your button on 100,640 point. Please ensure that your user control can accomodate your dynamic button. Otherwise, you won't see it.
I used your code and it worked fine for me, just ensure the proper size of both parent form and user control.
Most likely it is just that your button is being placed out of the bounds of the parent control and/or behind another control. I don't believe that UserControls or Forms are special in respect to adding controls at run-time, but a simple difference may be that Forms are by default re-sizable whereas UserControls aren't? Either way I don't think either Control type will automatically resize to fit all their child controls, so it's quite easy to put a new/dynamic control in the wrong place and have it not be visible.

Categories