This question already has answers here:
Find control by name from Windows Forms controls
(3 answers)
Closed 8 years ago.
I am creating new controls and putting there names in a list box, how do i use the name selected in the list box to change the controls properties.
//creating the label
LabelNumber++;
label label=new Label();
label.BackColor=Color.Transparent;
label.Location=new System.Drawing.Point(1,
1);
label.Name="Label" + LabelNumber;
label.Text=LabelNumber.ToString();
label.Size=new System.Drawing.Size(20,
20);
label.TextAlign=ContentAlignment.MiddleCenter;
ProjectPanel.Controls.Add(label);
ControlBox1.Items.Add(label.Name);
The question suggests that the OP is using a ListBox, so my code makes that assumption.
Essentially what you need to do is as follows: Get the selected text from the ListBox, find the control that has the same Name (we will assume this is always unique), then change the properties of that control.
The following code will meet those requirements:
// Get the selected text from the ListBox.
string name = ControlBox1.GetItemText(ControlBox1.SelectedItem);
// Find the control that matches that Name. Assumes there is only ever 1 single match.
Control control = ProjectPanel.Controls.Find(name, true).FirstOrDefault();
// Set properties of the Control.
control.Name = "new name";
// If you know it's a Label, you can cast to Label and use Label specific properties.
Label label = control as Label;
label.Text = "some new text";
Yo can use the Label Name under ControlBox1_SelectedIndexChanged event and get the value of selected indexed Label Name.
You can create a simple 'listboxitem' structure and use it like this:
struct lbo
{
// make the structure immutable
public readonly Control ctl;
// a simple constructor
public lbo(Control ctl_) { ctl = ctl_; }
// make it show the Name in the ListBox
public override string ToString() { return ctl.Name; }
}
private void button1_Click(object sender, EventArgs e)
{
// add a control:
listBox1.Items.Add(new lbo(button1));
}
private void button2_Click(object sender, EventArgs e)
{
// to just change the _Name (or Text or other properties present in all Controls)
((lbo)listBox1.SelectedItem).ctl.Text = button2.Text;
// to use it as a certain Control you need to cast it to the correct control type!!
((Button)((lbo)listBox1.SelectedItem).ctl).FlatStyle = yourStyle;
// to make the cast safe you can use as
Button btn = ((lbo)listBox1.SelectedItem).ctl as Button;
if (btn != null) btn.FlatStyle = FlatStyle.Flat;
}
No checks here for the correct type or that you have selected an item..but you get the idea: put something more useful than a naked object or a mere string into the ListBox!
You could instead loop over all controls and compare the names but that's less efficient and actually not safe as the Name property is not guaranteed to be unique..
Related
I'm trying to find a a way to be able to essentially dynamically generate code based on an input.
For example I could type something like:
int Number = 22;
Button<Number>.Text = "X";
So in this case it would set button22 to have its text be an "X".
And I could change it so that I could input, for example 24 into the program and it would then set button24 to be an "X", instead of setting up a bunch of if statements to cover every potential button press.
For further context I have a Grid of 64 buttons and I need to be able to edit them individually to show to the user which buttons have been pressed, it is possible to do it with a lot of if statements but I thought it might be worth trying to find a more elegant solution.
You could have a list of buttons:
private List<Button> _buttons = new List<Button>();
Populate it like this:
for (int i = 0; i < 10; i++)
{
var b = new Button();
b.Text = $"Button #{i}";
b.Click += HandleButtonClick;
}
And you could even set an event handler on one of its events which doesn't even need to use the list (the sender is the source of the event):
private void HandleButtonClick(object sender, EventArgs e)
{
(sender as Button).Text = "X";
}
Buttons have a Tag property that can be used to hold arbitrary data about a button, this is described for WinForms, WPF and UWP.
Simple usage that is similar to OP's requirement is demonstrated in this SO post
This situation is in a practical sense the very reason that .Tag exists at all in user interface controls pretty much from the birth of c#.
So you do not need to use a custom class for a button, just simply assign your value to the .Tag property on the Button class that you are creating programmatically:
in this example a list is used to create the buttons and separate the creation from the layout, it is not necessary to do this, but may be useful. Instead, you could assign this button to it's parent container and/or set the layout margins or coordinates without keeping a reference to the Button object at all.
If OP updates the post to include implementation examples, we can update this response with more specific and complete code.
private List<Button> _buttons = new List<Button>();
// ... iteration or switching logic
var nextButton = new Button
{
Text = "x",
Tag = 22
};
nextButton.Click += DynamicButton_Click;
_buttons.Add(nextButton);
// ... later push the buttons into the parent container or bind to the UI
Then the button click handler you can access this Tag property:
this is presented from WinForms, the only difference in UWP or WPF is the method signature, change EventArgs to RoutedEventArgs
private void DynamicButton_Click(object sender, EventArgs e)
{
if(int.TryParse((sender as Button).Tag?.ToString(), out int buttonValue))
{
// use buttonValue
Console.Out.WriteLine(buttonValue);
}
else
{
// Otherwise, sender was not a button, or the button did not have an integer tag value
// either way, handle that error state here...
}
}
Using these concepts, once the buttons are created, let's say in some simple grid alignment, you could allow the user to set this Tag value at runtime if you have a TextBox (or other) input field that can be accessed from the code.
I recommend that you use MVVM style bindings for this rather than directly referencing a TextBox control, but this is simply to demonstrate the point.
private void DynamicButton_Click(object sender, EventArgs e)
{
// assign the string value from the ButtonValueTextbox control to this button
string value = this.ButtonValueTextBox.Text;
if(sender is Button button)
{
button.Tag = value;
}
else
{
// Otherwise, sender was not a button
// handle the error state here if you need to...
}
}
Now that each button has a tag, you could easily add logic to maintain unique tag values by iterating through the other buttons and clearing the tag if it was previously assigned to a different button.
Maybe you could keep a List of Button References:
var myButtons = new List<Button>();
myButtons.Add(firstButton);
myButtons.Add(secondButton);
// ... etc
// ... then somewhere else
int number = 3;
myButtons[number].Text = "xxx";
I want to do something like this with windows forms:
Something like tags, but I only want label without colors and "x" value, I just want label with click event, how can I do it without using Telerik? it's not possible to do in datagrid view or something like that? Regards
Tag is a very common .Net property, so the question is bit unclear. But looking at the image and taking a wild guess on what you may want..:
If you want to have the ability to add Labels, let's call them TagLabels during runtime you may want to use a FlowLayoutPanel as their container. It will allow adding more and will take care of the layout no matter what sizes they have.
Example:
To create them we can use a TextBox, which we add to the FLP first. Then we code its PreviewKeyDown event and let the user create a new TagLabel by pressing enter..:
private void textBox1_PreviewKeyDown(object sender, PreviewKeyDownEventArgs e)
{
if (e.KeyCode == Keys.Enter && textBox1.Text != "")
{
Label lbl = new Label {
Text = " " + textBox1.Text, /* some room for the image */
BorderStyle = BorderStyle.Fixed3D,
TextAlign = ContentAlignment.MiddleCenter,
AutoSize = true,
Margin = new Padding(2),
ImageIndex = flowLayoutPanel1.Controls.Count %
imageList1.Images.Count,
ImageList = imageList1,
ImageAlign = ContentAlignment.MiddleLeft,
MinimumSize = new Size(100, 20),
BackColor = Color.LightGoldenrodYellow,
Name = "TagLabel" + (flowLayoutPanel1.Controls.Count)
};
lbl.MouseClick +=lbl_MouseClick ;
flowLayoutPanel1.Controls.Add(lbl);
flowLayoutPanel1.Controls.SetChildIndex(lbl,
flowLayoutPanel1.Controls.Count - 2);
textBox1.Text = "";
}
else
if (e.KeyCode == Keys.Escape)
{
textBox1.Text = "";
}
}
The Click event should be generic for all labels; so we first cast sender to Label and can then code the processing..:
private void lbl_MouseClick(object sender, MouseEventArgs e)
{
Label lbl = sender as Label;
//...
MessageBox.Show(lbl.Name + " : Ouch! You clicked on " + lbl.Text.Trim());
}
This is just a basic piece of code. You can style the labels any way you want and of course also include code for deleting, maybe with a context menu. If those labels shall carry more responsibility, you can and should create a class, probably a Label subclass to hold further data and methods..
I'm also using an ImageList to display images to the left. Do change these details to suit your needs!
Note that there is no reasonable way to add the FLP to an ordinary DataGridView. You may be able to workaround but depending on your needs it may be best to keep them separate. DGVs have Cells and while these can hold special controls this is complicated and will always be restricted by the cells' i.e. the Columns' and the Rows' Size. As an alternative you can check out this example to see how you can insert virtual space to a row to hold a control but neither DGV nor its Cells are containers.
I'm trying to get the value of items in a dynamically made combobox from a separate event. I need to put the value the user chose into a string, but I can't find a way to do it. Here's an example.
ComboBox player1Role = new ComboBox();
player1Role.Width = 100;
player1Role.Items.Add("Top");
player1Role.Items.Add("Jungle");
player1Role.Items.Add("Mid");
player1Role.Items.Add("Bot");
player1Role.Items.Add("Support");
player1Role.Items.Add("Fill");
player1Role.Location = new Point(200, 200);
And then in the following click event, I need to get the value they selected:
private void CreateParty_Click(object sender, EventArgs e)
{
ComboBox player1SelectedRole = (ComboBox)Controls["player1Role"];
string player1roleString = player1SelectedRole.Items[0].ToString();
MessageBox.Show(player1roleString);
}
That code just gives me an exception saying player1SelectedRole was empty. What am I doing wrong?
You're looking for the control by its name, but you didn't assign a name to the control.
player1Role.Name = "player1Role";
Also, I think player1SelectedRole.Items[0] is always going to select the first item regardless of which one is actually selected. Check out player1SelectedRole.SelectedItem instead.
OK so I have to work with lots of toggle button and textbox, so I named them in such way that adding letter "Q" to button's name will give name of the textbox that the button corresponds to. I have link all the button to the same method on checked event, and using this naming mechanism I, hope to manipulate the textbox corresponding the button.
What I have done till now is, generate an name of the textbox in string format. But i don't know to how to use this string to manipulate the textbox.
private void OnbuttonClick(object sender, RoutedEventArgs e)
{
ToggleButton tb = (ToggleButton)sender;
if(tb.IsChecked==true)
{
string tbnam = ((ToggleButton)sender).Name;
string name2 = tbnam + "Q";
?????? (what happens from this point onward)
}
}
"name2" is the name of textbox that corresponds to the toggle button of name "tbnam".
I hope the I have made the problem clear.
In WPF, a much better way to do this would to expose a collection of objects in the viewmodel, and display in the UI with an ItemsControl with an ItemTemplate that would dynamically create as many iterations of ToggleButton/TextBox pairs as needed. I'd be happy to go into how to do that, if you're interested.
But for now, you can get your code working using the FindName(string) method:
private void Button_Click(object sender, RoutedEventArgs e)
{
ToggleButton tb = (ToggleButton)sender;
if (tb.IsChecked == true)
{
string name2 = tb.Name + "Q";
TextBox tbox = FindName(name2) as TextBox;
// Check to see if tbox is null, do stuff with it
}
}
How do I create a control in a windows form application? I want to generate a textbox or a radio button when I select something from a Combobox. I basically want to query my database, and based on the values of the fields, I want to generate a textbox or a radio button. For example, if my query returns a value of "Textbox", I want to generate a textbox on the form in a specified location. How does one accomplish this? Please help.
The easiest way is to create the control manually in code and then add it to the Controls collection. Deciding which control to create depending on some input data (whether it's database query or a value selected from a combobox) is not much different then in any other case. Simple if will do the job. For instance:
private void AddControl(string control)
{
if (control == "Textbox")
{
TextBox tb = new TextBox();
tb.Location = new Point(100, 100);
this.Controls.Add(tb);
}
else if (control == "Radio")
{
RadioButton rb = new RadioButton();
rb.Location = new Point(200, 100);
this.Controls.Add(rb);
}
}
Of course, it's very naive version. But it's only a starting point. I leave to you adding more advanced logic (like dynamically adjusting location, setting up properties of the radio button or the textbox, relying on Type instead of on a simple string, etc.)
The assumption is that you retrieve a string value from the database. For example in form's constructor:
public Form1()
{
InitializeComponent();
string requestedControl = QueryDatabase();
AddControl(requestedControl);
}
I leave to you implementing the method to query the database.
In the question you also mentioned adding a control after selecting it in the combobox. In this case the only difference is that you rely on an event triggered after combobox's selection changed:
private void comboBox1_SelectedValueChanged(object sender, EventArgs e)
{
string res = this.comboBox1.SelectedItem.ToString();
this.AddControl(res);
}
Here you rely on SelectedValueChanged event. Of course, in this case your combobox has to be populated with expected values (here "Radio" and "Textbox"). Also, you have to attach the event handler to the specific event on the combobox. You can do that in designer or by adding in the constructor the following line:
combobox1.SelectedValueChanged += comboBox1_SelectedValueChanged;
Hope that clarifies the issue and sets up some starting point for you to continue from.