Finding and manipulating a UI control with a particular Name - c#

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
}
}

Related

Is there a way to dynamically generate code to interact with buttons in C#?

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";

Convert a string value into PlaceHolder id

As a newbie I have tried several Google searches and have found a few confusing answers. What I am trying to achieve is:
click on a button (one of many),
extract that button's text value, then
use that value to make the relevant placeholder visible.
So far I have done the first 2 steps but how do I accomplish step 3? My code so far, which works if I click on the Asia button, is:
protected void btnArea_Click(object sender, EventArgs e)
{
string ar = (sender as Button).Text;
//ar = "Asia";
phdasia.Visible = true;
}
In simple, newbie friendly terms, what do I have to insert in place of phdasia?
If your placeholder controls share the same name format you may be able to reach them by name:
protected void btnArea_Click(object sender, EventArgs e)
{
string ar = (sender as Button).Text;
//ar = "Asia";
string name = "phd" + ar.ToLower(); // The naming format comes here
Control[] controls = this.Controls.Find(name, true); //find the control(s) by name
foreach(Control control in controls) // mow loop and make them visible
control.Visible = true;
//phdasia.Visible = true;
}
Edit: alternatively you can use FindControl method to locate a control with an ID property of "phdasia" on the containing page:
Control control = FindControl(name);
if(control!=null)
control.Visible = true;

c# listbox with control names to change properties [duplicate]

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..

Data binding to list and dynamically adding controls using Windows Forms

I have a List<Appointment> where an Appointment is.
public class Appointment
{
public string Title { get; set; }
public string Start { get; set; }
public string End { get; set; }
}
I want to dynamically add each list item on a separate line on the form like so:
item.Title + " between" + item.Start + " and " + item.End;
I want to be able to click each item (the text), then with each click it can toggle the colour of the text between red and black (that is, if black it turns red, if red it turns black when you click).
I come from a web background, but I am just struggling with Windows Forms data binding. I've tried with table layout panel but just don't know where to begin with changing the color of an item on click.
PS: If it helps, the number of items in the list will probably not be more than 10.
I've gotten a bit further as per Jamie Ide's comment:
var appts = GetAllCalendarItems();
foreach (var item in appts)
{
Label label = new Label();
label.Text = item.Title + " between" + item.Start + " and " + item.End;
label.Click += new EventHandler(label_Click);
flowLayoutPanel1.Controls.Add(label);
}
...
private void label_Click(object sender, EventArgs e)
{
// This is wrong - what goes here??
((Label)sender).ForeColor = Color.Red;
}
Dynamically laying out Windows Forms is a huge pain. I don't have time to code this but the steps are:
Add FlowLayoutPanel to form as a container
Look through your Appointments and create label controls for each
Add the label controls to the panel's Controls collection
Assign an OnClick handler to each label control to toggle the color
Don't bother with databinding for this.
If you haven't changed the label's initial color from the default, this will toggle it:
private void label1_Click(object sender, EventArgs e)
{
var lbl = (Label)sender;
var toggle = lbl.ForeColor == SystemColors.ControlText;
lbl.ForeColor = toggle ? Color.Red : SystemColors.ControlText;
}
You could add each text field as a member of a Label or List view item. Then handle the "OnClick" or "SelectedIndexChanged" event. To create an an OnClick event handler double click on the control in the design view. Edit the handler like this:
private void listView1_SelectedIndexChanged(object sender, EventArgs e)
{
listView1.SelectedItems[0].ForeColor = Color.Red;
}
If you are unsure about event handlers, don't be put off they are quite easy, just look them up here perhaps. If the list view is not what you are looking for, try the same approach on a different control.
I guess I can't comment on Jamie's answer, but raklos you can programmatically add the OnClick method by doing:
label.Click += new EventHandler(label_Click);
Visual Studio should auto-generate the stubs for you when you start typing that out.
Something like this could get you started:
private void label_Click(object sender, EventArgs e) { ToggleTextColor((Label)sender); }
private void ToggleTextColor(Control control)
{
var currentColor = control.ForeColor;
control.ForeColor = currentColor == Color.Red ? Color.Black : Color.Red;
}
You can cheat and make create it in a WebBrowserControl.
You will be in familiar ground.
Use ObjectforScripting for WeBbrowser <=> winforms communication.
http://msdn.microsoft.com/en-us/library/system.windows.forms.webbrowser.objectforscripting.aspx

C# ComboBox in DropDownList style, how do I set the text?

I want to use a ComboBox with the DropDownList style (the one that makes it look like a button so you can't enter a value) to insert a value into a text box. I want the combobox to have a text label called 'Wildcards' and as I select a wildcard from the list the selected value is inserted in to a text box and the combobox text remains 'Wildcard'. My first problem is I can't seem to set a text value when the combobox is in DropDownList style. Using the properties pallet doesn't work the text value is simply cleared when you click off, adding comboBox.Text = "Wildcards"; to form_load doesn't work either. Can anyone help?
The code you specify:
comboBox.Text = "Wildcards";
...should work. The only reason it would not is that the text you specify is not an item within the comboBox's item list. When using the DropDownList style, you can only set Text to values that actually appear in the list.
If it is the case that you are trying to set the text to Wildcards and that item does not appear in the list, and an alternative solution is not acceptable, you may have to be a bit dirty with the code and add an item temporarily that is removed when the drop-down list is expanded.
For example, if you have a form containing a combobox named "comboBox1" with some items and a button named "button1" you could do something like this:
private void button1_Click(object sender, EventArgs e)
{
if (!comboBox1.Items.Contains("Wildcards"))
{
comboBox1.Items.Add("Wildcards");
}
comboBox1.Text = "Wildcards";
}
private void comboBox1_DropDown(object sender, EventArgs e)
{
if (comboBox1.Items.Contains("Wildcards"))
comboBox1.Items.Remove("Wildcards");
}
That's pretty quick and dirty but by capturing the DropDownClosed event too you could clean it up a bit, adding the "Wildcards" item back as needed.
You can select one of items on formload or in form constructor:
public MyForm()
{
InitializeComponent();
comboBox.SelectedIndex = 0;
}
or
private void MyForm_Load(object sender, EventArgs e)
{
comboBox.SelectedIndex = 0;
}
Try this
comboBox1.SelectedValue = "Wildcards";
This may be a possible solution:
comboBox1.SelectedValue = comboBox1.Items.FindByText("Wildcards").Value;

Categories