How to add and remove "custom" tabs in C# - c#

I am making an application that requires tabs (tab-control) to be added or removed. I have done the add and remove for tabs fine, but I have custom buttons instead of using the tabs. (This button will go the the first tab page when clicked):
//This will make it go to TAB 1
private void button1_Click(object sender, EventArgs e)
{
tabControl1.SelectedIndex = 0;
}
//This will change the MOUSEENTER to the correct image
private void button1_MouseEnter(object sender, EventArgs e)
{
button1.MouseEnter += new EventHandler(button1_MouseEnter);
this.button1.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.Tab_Down));
}
//This will change the MOUSELEAVE to the correct image
private void button1_MouseLeave(object sender, EventArgs e)
{
button1.MouseLeave += new EventHandler(button1_MouseLeave);
this.button1.BackgroundImage = ((System.Drawing.Image)(Properties.Resources.Tab_Norm));
}
However, how will I create it so when you click the "Add Tab" button it creates a new tab but it also creates a new button with tabControl1.SelectedIndex = 1; in it for example.
Edit
I have done this to add a new tab (to tabControl1):
private void button2_Click(object sender, EventArgs e)
{
string title = "TabPage " + (tabControl1.TabCount + 1).ToString();
TabPage myTabPage = new TabPage(title);
tabControl1.TabPages.Add(myTabPage);
}
This adds a new tab on top of the existing ones fine. But I how do I do it so that it also creates a new button with the properties of the button above but makes it so instead of tabControl1.SelectedIndex = 1; it does tabControl1.SelectedIndex = 3; and goes up every time I add a new tab? - Thanks

After a few updates here is a new version of my answer. It shows you how to
Add a Button which adds a new TabPages and selects it
Make the Tab control draw closing 'x' characters to the right of each tab, like Firefox or Visual Studio do it.
Make the add Button like you want it, maybe the Text="+" and the height like the tabs' height. It is automatically positioned on the tab. You may need to reposition it, if your Tab is moved or resized.
In the Form_Load event the Tab is set to OwnerDrawFixed and each page's text is append by a few blanks to make room for the closing x. The code creates a class variable closeX to hold the current x-rectangle and tests it in the MouseClick event.
Make sure to wire up the tabControl1_DrawItem and tabControl1_MouseClick events!
private void cb_addPage_Click(object sender, EventArgs e)
{
string title = "TabPage " + (tabControl1.TabCount + 1).ToString() + " ";
TabPage myTabPage = new TabPage(title);
tabControl1.TabPages.Add(myTabPage);
tabControl1.SelectedTab = myTabPage;
}
private void Form1_Load(object sender, EventArgs e)
{
tabControl1.DrawMode = TabDrawMode.OwnerDrawFixed;
cb_addPage.Top = tabControl1.Top;
cb_addPage.Left = tabControl1.Right - cb_addPage.Width;
foreach (TabPage tp in tabControl1.TabPages) tp.Text += " ";
}
Rectangle closeX = Rectangle.Empty;
private void tabControl1_DrawItem(object sender, DrawItemEventArgs e)
{
Size xSize = new Size(13,13);
TabPage tp = tabControl3.TabPages[e.Index];
e.DrawBackground();
using (SolidBrush brush = new SolidBrush(e.ForeColor) )
e.Graphics.DrawString(tp.Text+ " ", e.Font, brush,
e.Bounds.X + 3, e.Bounds.Y + 4 );
if (e.State == DrawItemState.Selected)
{
closeX = new Rectangle(
e.Bounds.Right - xSize.Width, e.Bounds.Top, xSize.Width, xSize.Height);
using (SolidBrush brush = new SolidBrush(Color.LightGray))
e.Graphics.DrawString("x", e.Font, brush,
e.Bounds.Right - xSize.Width, e.Bounds.Y + 4);
}
}
private void tabControl1_MouseClick(object sender, MouseEventArgs e)
{
if (closeX.Contains(e.Location))
tabControl1.TabPages.Remove(tabControl1.SelectedTab);
}
If you want to use an Image to adorn the tabs, include an ImageList with your form, load it with the Image(s) and if the close button is the 1st image, change the code like this:
if (e.State == DrawItemState.Selected)
{
closeX = new Rectangle(e.Bounds.Right - xSize.Width - 3,
e.Bounds.Top + 5, xSize.Width, xSize.Height);
e.Graphics.DrawImage(imageList1.Images[0], closeX,
new Rectangle(0,0,16,16), GraphicsUnit.Pixel );
}
I append a screenshot of the Tab with a few pages
And one using this close button image:
Update: Note that if your TabPage contains IDisposable objects you should make sure they all get disposed before you remove the page! See here for example code!

Related

C# Switch tabs(tabcontrol) while dragging a watermark picbox and hovering over a tab

In one of my posts(the link below), I ask how to change tabs while dragging a treenode and hovering over a tab. Now I want do the same thing except with a watermark picbox that is inside another picturebox(a parent sort of speak) that inside a tab.There are two tab pages, two "parent" picboxes(one foreach tab) and one dynamically added picbox on first tab. For more detail read the numbered list below also the code you will need is below the link.
The parent picboxes in both tabs are maxed out in both height and in width to fit the whole tabpage(NOT the header area). The watermark image size is below in the code. Also the watermark is dynamically added.
The reason this semi-copy of the older post failed is because the watermark drag enter event was never called. Meaning the tab never opened after the pic was dragged and was hovering over one of the tabs.Though I'm not 100% sure if I should use the same event with picboxes.
I want to know how I can open tabs while dragging a picbox and hovering over a tab and be able to drop the watermark image on the 2nd parent picbox in tabpage#2 and remove the watermark image in tabpage 1 if there is a copy of the same watermark image.
C# Switch tabs(tabcontrol) while dragging and hovering over a tab
Point mousePos;
bool Movedummytonewtabpic = false;
private void Form1_Load(object sender, EventArgs e)
{
PictureBox picdrag1 = new PictureBox();
picdrag1.Name = "dummytest";
picdrag1.Image = Properties.Resources._previmg;
picdrag1.Size = new Size(52, 42);
picdrag1.SizeMode = PictureBoxSizeMode.AutoSize;
picdrag1.MouseDown += picdrag1_MouseDown;
picdrag1.MouseMove += picdrag1_MouseMove;
picdrag1.DragEnter += picdrag1_DragEnter;
picdrag1.Location = new Point(168, 151);
pictureBox1.Controls.Add(picdrag1);
}
private void picdrag1_DragEnter(object sender, DragEventArgs e)
{
//DragDropEffects.
e.Effect = DragDropEffects.Copy;
Movedummytonewtabpic = true;
}
private void picdrag1_MouseDown(object sender, MouseEventArgs e)
{
mousePos = e.Location;
}
private void picdrag1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
int dx = e.X - mousePos.X;
int dy = e.Y - mousePos.Y;
pictureBox1.Location = new Point(pictureBox1.Left + dx, pictureBox1.Top + dy);
}
}
private void tabControl1_DragOver(object sender, DragEventArgs e)
{
if (Movedummytonewtabpic == true )
{
//e.Effect = DragDropEffects.All;
Point clientPoint = tabControl1.PointToClient(new Point(e.X, e.Y));
for (int i = 0; i < tabControl1.TabCount; i++)
{
if (tabControl1.GetTabRect(i).Contains(clientPoint) && tabControl1.SelectedIndex != i)
{
tabControl1.SelectedIndex = i;
}
}
}
}

How to know what Linklabel has been clicked?

Background
I have created 8 linklabels which are created using a loop which gets data from a database.
Each record fills a linklabel.
How ever how can I distinguish what linklabel has been clicked on?
Code
for (int i = 0; i <= rowCount - 1; i++)
{
LinkLabel Linklabel = new LinkLabel();
Linklabel.Text = ds.Tables[0].Rows[i]["code"].ToString();
Linklabel.Height = 15;
Linklabel.Width = 50;
Linklabel.AutoSize = true;
Linklabel.Location = new Point(10, (i + 1) * 30);
tabControl1.TabPages[0].Controls.Add(Linklabel);
// Add an event handler to do something when the links are clicked.
Linklabel.LinkClicked += new System.Windows.Forms.LinkLabelLinkClickedEventHandler(this.linkLabel1_LinkClicked);
}
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
tabControl1.SelectedTab = tabPage2;
}
When clicking on any of the 8 linklabels that are drawn the same thing will happen.
What I would like to happen?
When clicking on any of the linklabels I would like to change a label.text to what the contents of the clicked linklabel was.
For example
If the first linklabel.text=("one") is clicked on label1.text becomes one.
If the second linkedlabel.text=("two") is clicked on label1.text becomes two.
You could use the sender argument in the callback which will point to the actual LinkLabel being clicked:
private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
{
label1.text = ((LinkLabel)sender).Text;
}

C# - Drag and Drop & Keep Control: Extension

sorry to bother again with a similar question. However, I have an issue with my code again in C#. I would like to give you the code I have got so far:
private void pictureBox2_Click(object sender, EventArgs e)
{
PictureBox flower2 = new PictureBox();
flower2.Image = Properties.Resources.Flower3;
flower2.Location = new Point(panel1.Location.X + 10, panel1.Location.Y + 10);
flower2.Size = new System.Drawing.Size(pictureBox2.Size.Width, pictureBox2.Size.Height);
flower2.Parent = panel1;
this.Controls.Add(flower2);
flower2.BringToFront();
flower2.MouseMove += new MouseEventHandler(flower2_MouseMove);
flower2.MouseDown += new MouseEventHandler(flower2_MouseDown);
}
private void flower2_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
MouseDownLocation = e.Location;
}
}
private void flower2_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
flower2.Left = e.X + flower2.Left - MouseDownLocation.X;
flower2.Top = e.Y + flower2.Top - MouseDownLocation.Y;
}
}
What I wanted it to do is when an image is clicked, create a new one and be able to drag and drop it. I succeeded only when I put my code at the top of the page. Which is not what I want because I want to be able to add as many images as I would like. I tried alot of different methods. The errors are at:
flower2.Left = e.X + flower2.Left - MouseDownLocation.X;
flower2.Top = e.Y + flower2.Top - MouseDownLocation.Y;
At all the words under the name of flower2. This is because, I have defined flower2 in pictureBox2_Click so everytime it's clicked a new PictureBox will generate. But, I need to make it so I can generate as many images as I want and without putting it at the top of the page, this makes it so it only uses one image at a time.
Each picturebox you make is routed to those events, thus the sender object is the picturebox, you just need to cast it to the right type then move that.
PictureBox pb = (PictureBox)sender;
pb.Left = e.X + pb.Left - MouseDownLocation.X;

Drawn line isn't shown on a combobox

I need your help in following question (using .Net 3.5 and Windows Forms):
I just simply want to draw a line on a middle of a combobox (Windows Forms) that is situated on a form.
The code I use is:
void comboBox1_Paint(object sender, PaintEventArgs e)
{
e.Graphics.DrawLine(new Pen(Brushes.DarkBlue),
this.comboBox1.Location.X,
this.comboBox1.Location.Y + (this.comboBox1.Size.Height / 2),
this.comboBox1.Location.X + this.comboBox1.Size.Width,
this.comboBox1.Location.Y + (this.comboBox1.Size.Height / 2));
}
To fire a paint event:
private void button1_Click(object sender, EventArgs e)
{
comboBox1.Refresh();
}
When I execute the code and press button the line isn't drawn. In debug the breakpoint at the paint handler isn't being hit. The strange thing is that on MSDN there is a paint event in ComBox's events list, but in VS 2010 IntelliSense doesn't find such event in ComboBox's members
Thanks.
public Form1()
{
InitializeComponent();
comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
comboBox1.DrawItem += new DrawItemEventHandler(comboBox1_DrawItem);
}
void comboBox1_DrawItem(object sender, DrawItemEventArgs e) {
e.DrawBackground();
e.Graphics.DrawLine(Pens.Black, new Point(e.Bounds.Left, e.Bounds.Bottom-1),
new Point(e.Bounds.Right, e.Bounds.Bottom-1));
TextRenderer.DrawText(e.Graphics, comboBox1.Items[e.Index].ToString(),
comboBox1.Font, e.Bounds, comboBox1.ForeColor, TextFormatFlags.Left);
e.DrawFocusRectangle();
}
Paint event will not fire.
What do you want is possible only when DropDownStyle == ComboBoxStyle.DropDownList:
comboBox1.DrawMode = DrawMode.OwnerDrawFixed;
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
comboBox1.DrawItem += (sender, args) =>
{
var ordinate = args.Bounds.Top + args.Bounds.Height / 2;
args.Graphics.DrawLine(new Pen(Color.Red), new Point(args.Bounds.Left, ordinate),
new Point(args.Bounds.Right, ordinate));
};
This way you can draw selected item area yourself.

Windows Forms right-click menu for multiple controls

I have several controls in a Windows Form and I want an identical menu to popup on each when right-clicked. However, the action should vary slightly based on which control was clicked.
The problem I'm having is that the ToolStripMenuItem doesn't have any information about which control was originally clicked to make the tool strip visible. I really don't want to need a separate context menu for each control!
Thus far my code looks something like:
private void InitializeComponent()
{
this.openMenuItem = new ToolStripMenuItem();
this.openMenuItem.Text = "Open";
this.openMenuItem.Click += new EventHandler(this.openMenuItemClick);
this.runMenuItem = new ToolStripMenuItem();
this.runMenuItem.Text = "Run";
this.runMenuItem.Click += new EventHandler(this.runMenuItemClick);
this.contextMenuStrip = new ContextMenuStrip(this.components);
this.contextMenuStrip.Items.AddRange(new ToolStripMenuItem[]{
this.openMenuItem,
this.runMenuItem});
this.option1 = new Label();
this.option1.Click += new EventHandler(this.optionClick);
this.option2 = new Label();
this.option2.Click += new EventHandler(this.optionClick);
}
void optionClick(object sender, EventArgs e)
{
MouseEventArgs mea = e as MouseEventArgs;
Control clicked = sender as Control;
if(mea==null || clicked==null) return;
if(mea.Button == MouseButtons.Right){
this.contextMenuStrip.Show(clicked, mea.Location);
}
}
void openMenuItemClick(object sender, EventArgs e)
{
//Open stuff for option1 or option2, depending on which was right-clicked.
}
void runMenuItemClick(object sender, EventArgs e)
{
//Run stuff for option1 or option2, depending on which was right-clicked.
}
Within runMenuItemClick you need to cast then sender to a ToolStripMenuItem and then cast its owner to a ContextMenuStrip. From there you can look at the ContextMenuStrip's SourceControl property to get the name of the control that clicked the item.
void runMenuItemClick(object sender, EventArgs e) {
var tsItem = ( ToolStripMenuItem ) sender;
var cms = ( ContextMenuStrip ) tsItem.Owner;
Console.WriteLine ( cms.SourceControl.Name );
}

Categories