I am creating dynamically buttons in windows forms by using the code below. I want to have a context menu with different options pop up when a button is being right clicked. I made the context menu strp and it shows up but i cant figure out how to make the different options perform the functions i have written for them. Any idea how i can connect the items to their functions ?
void AddButton(Shape s){
Button b = new Button();
b.Text = s.name;
b.Width = sceneItemsList.Width-6;
b.TabStop = false;
b.FlatStyle = FlatStyle.Flat;
b.BackColor = Color.LightGray;
b.FlatAppearance.BorderColor = Color.Black;
ContextMenuStrip cm = new ContextMenuStrip();
cm.Items.Add("Deselect");
cm.Items.Add("Edit");
if (s is GroupShape)
{
cm.Items.Add("Ungroup");
}
cm.Items.Add("Delete");
b.ContextMenuStrip = cm;
}
Figured it out! This is my code if anyone else is struggling with this. Basically you make a loop that goes through all the opptions and adds a click eventhadler
cm.Items[0].Click += (sender, e) => {
Console.WriteLine("ok");
};
Related
i'm working in ASP.NET in visual studio.
I tried to dynamicly create a list of buttons in C# and make its appears on an update panel, and it worked.
My problem is the following : i've created this list with a for loop and so, every buttons has the same OnClick method. So, when i click on one of its, it doesn't do anything.
Do you have any ideas of what my problem can be ?
this is my for loop for creating :
for (int i = 1; i < eq.Count; i += 3)
{
Button nom = new Button();
nom.Text = "btn-"+ Convert.ToString(i);
nom.ID = ("Nom" + i).ToString();
nom.Click += new EventHandler(btn_Agent_Click);
Panel.Controls.Add(nom);
Button refurl = new Button();
refurl.Text = equipes[i + 2];
refurl.ID = ("refURL" + i).ToString();
indice++;
}
Have a great day ! :)
I have achieved creating dynamic buttons using the following code for click event
nom.Click += (s, e) => {
// add your logic here for each button where s,e are (object sender, EventArgs e)
};
Hope it helps!
I'm new working with C# and I'm asking on here because I didn't find a solution searching in google and other questions on SO, I will explain what my example application does:
When I run it it display a form with a textbox by default, this textbox always will be shown, after type some text and press enter it will generate a new textbox and a new button (all the controls even the default textbox are inside a panel), and the new textboxes have the same functionality as the default textbox, when I click on the button generated next to its textbox it removes the button itself and the textbox but after that if I remove some random textboxes it leaves a space between these controls, how can reorganize this content to dont let space between them?
As you can see in the image, can you tell me how can fix this or give me an advice to achieve this? thank you, by the way this is the method I use to generate the buttons and textboxes
private void GenerarTextBox()
{
panelContenedor.VerticalScroll.Value = panelContenedor.VerticalScroll.Minimum;
TextBox tb = new TextBox();
tb.Text = "Prueba " + id;
tb.Name = "txtBox" + id;
tb.KeyDown += new KeyEventHandler(TextBox_Keydown);
Button bt = new Button();
bt.Cursor = Cursors.Hand;
bt.Text = "X";
bt.Name = "btnPrueba" + id;
bt.Click += new EventHandler(ClickBotones);
Point p = new Point(20, 30 * id);
Point pb = new Point(130, 30 * id);
tb.Location = p;
bt.Location = pb;
panelContenedor.Controls.Add(tb);
panelContenedor.Controls.Add(bt);
tb.Focus();
id++;
}
And this to remove the textboxes and the buttons
private void ClickBotones(object sender, EventArgs e)
{
Button bt = sender as Button;
string nombreBoton = bt.Name;
string idBoton = nombreBoton.Substring(9);
string nombreTextBox = "txtBox" + idBoton;
foreach (Control item in panelContenedor.Controls.OfType<Control>())
{
if (item.Name == nombreTextBox)
{
panelContenedor.Controls.Remove(item);
panelContenedor.Controls.Remove(bt);
}
}
}
You could place your dynamic controls on a FlowLayoutPanel. Either directly or grouped together in a Panel or UserControl.
Set the FlowDirection property of the FlowLayoutPanel to TopDown. The FlowLayoutPanel will then arrange your controls automatically. You can also set the WrapContents property to False and AutoScroll to true to make the scroll bar appear.
Alternatively you can use FlowDirection = LeftToRight, place the text box and the button directly on the FlowLayoutPanel and let the child controls wrap (WrapContents = True). In the child controls, a new property FlowBreak appears. It can be set to True for the last control to appear in a row and let the next one wrap independently of the width of the FlowLayoutPanel.
You can also play with the Margin property of the child controls to control their layout in the FlowLayoutPanel as the Location property becomes useless.
The FlowLayoutPanel (as well as the Panel) is available in the Toolbox in the section "Containers".
When you delete the controls, you need to do a recalc of the positions. So when you have added them in sequence, you can go with:
bool repos = false;
Point p;
foreach (Control item in panelContenedor.Controls.OfType<Control>())
{
if (repos)
{
Point tmp = item.Location;
item.Location = p;
p = tmp;
}
if (item.Name == nombreTextBox)
{
panelContenedor.Controls.Remove(item);
panelContenedor.Controls.Remove(bt);
repos = true;
p = item.Location;
}
}
I'm currently trying to add some custom controls to a panel in winforms.
Every control will be docked and build something like a "list".
Now i'm trying to implement a feature to select/deselect every control.
Its working fine, my problem is that it seems to be very slow sometimes.
Currently its about ~50 custom controls in the panel.
modtable.Click += (s, e) =>
{
foreach (Control m in pnl_ucMods.Controls)
{
if(m is ModTableEntry)
{
if(m != modtable)
{
((ModTableEntry)m).BackColor = SystemColors.Control;
}
else if (m == modtable && m.BackColor == SystemColors.Control)
m.BackColor = SystemColors.ActiveCaption;
else
m.BackColor = SystemColors.Control;
}
}
};
Whenever i click on one of the controls it will change the backcolor, on a second click it will change it back but thats only working if i wait like a second before i click again. If i click to fast, nothing happens and i have to click again.
I understand that winforms is not designed to have tons of controls and i understand that foreach will need some time to loop through all the controls, but maybe someone here has a small idea how to improve the code and maybe solve this problem.
tl;dr
Click on one of the custom controls in the panel will change its backcolor. (Selected)
Every other control will change the backcolor too (deselected)
If the clicked control is already selected, it will deselect.
EDIT:
A small example to test that problem.
Just create a new project, add the code and call it.
private void addPanels()
{
Panel newPanel = new Panel();
newPanel.AutoScroll = true;
newPanel.Dock = DockStyle.Fill;
this.Controls.Add(newPanel);
for (int i = 0; i < 50; i++)
{
Panel childPanel = new Panel();
childPanel.Size = new Size(100, 30);
childPanel.Dock = DockStyle.Top;
childPanel.Click += (s, e) =>
{
foreach (Control p in newPanel.Controls)
{
if (p is Panel)
{
if (p != childPanel)
((Panel)p).BackColor = SystemColors.Control;
else if (p == childPanel && p.BackColor == SystemColors.Control)
p.BackColor = SystemColors.ActiveCaption;
else
p.BackColor = SystemColors.Control;
}
}
};
newPanel.Controls.Add(childPanel);
}
}
Use MouseDown event instead of Click event.
When you click twice too fast, it would be a DoubleClick event and no other Click event will raise.
With your permission, Reza.
I have a form over which I have a panel. When a button is clicked, I turn my panel to invisible and I show a DataGridView ( a table from sql ). My problem is... is there any way to put a button somewhere on my form so I can go back to the main menu ( on click, to set the panel visibility to true ).
I tried using DataGridViewButtons but it's not ok. I want just one single button, anywhere on my form, called Back that would take me back. Somehow, it won't let me place a button anywhere unless I have a panel. Is there any solution?
I can add any code if necessary, just tell me which
menu.Visible = false;
DataGridView dgw = new DataGridView();
dgw.Parent = this;
dgw.Location = new Point(
this.ClientSize.Width / 3 - dgw.Size.Width / 2,
this.ClientSize.Height / 4 - dgw.Size.Height / 2);
dgw.Anchor = AnchorStyles.None;
dgw.AutoSize = true;
dgw.BackColor = Color.FromArgb(210, 121, 84);
dgw.Text = "Login";
dgw.Padding = new Padding(10);
dgw.BorderStyle = BorderStyle.FixedSingle;
While it is far more easy to create your form from the designer, placing a Button on the form code is as simple as creating the datagrid.
private void CreateButton()
{
var button = new Button
{
Text = "Press me",
Name = "SomeButtonName",
Location = new Point(10,10),
Size = new Size(100,20),
Visible = true,
};
button.Click += (s, e) => this.ButtonClicked();
this.Controls.Add(button);
}
private void ButtonClicked()
{
// this will fire on click
}
You can call `this.CreateButton()' everywhere you'll like.
I use this solution(in code below) to add multiply buttons on panel. It works ok but it takes too long, when it tries to add a lot of buttons (for an example 40). I want to ask, if any one knows of a better solution for this situation? I was thinking of creating all possible buttons at program start-up, but in this case will start-up take too long, especially if there will be really lot of buttons (this scenario is possible)?
while (data.Read())
{
btnName = Convert.ToString(data["Name"]);
btnColor = (color == string.Empty) ? Convert.ToString(data["Color"]) : color;
categoryId = Convert.ToInt16(data["CategoryId"]);
//both category and article table's contains this data!
if (categoryId == articleCatId || cl == typeof(Category))
{
Button newbtn = new Button();
newbtn.TextAlign = ContentAlignment.MiddleCenter;
newbtn.Click += (sender, e) => method(sender, e);
newbtn.Text = btnName;
newbtn.Name = "button-" + btnName;
newbtn.Height = size;
newbtn.Width = size;
newbtn.Font = new Font("Microsoft Sans Serif", fontH);
newbtn.Location = new Point(paddingL, paddingT);
newbtn.BackColor = ColorTranslator.FromHtml(btnColor);
location.Controls.Add(newbtn);
num += 1;
if ((num - 1) / inline == 1) { paddingT += size; paddingL = 2; num = 1; }
else { paddingL = paddingL + size; }
}
}
You probably cannot reduce the number of buttons you need to create, so you then have some options to speed it up a little bit:
Add the buttons to an object that is not visible. Only when you're done adding buttons, you make the object visible.
Call SuspendLayout on the parent control to stop it from trying to layout itself. Then call ResumeLayout when you're done adding buttons.
Use a more lightweight control than a button, that is more appropriate for the task. For example a Listbox, Combobox, or several checkboxes or option buttons styled as normal buttons.
Write your own lightweight Button control that does exactly what you want but no more.