How to find dynamically created XAML component by Name in C#? - c#

How to find dynamically created XAML component by Name in C#?
I created next button and put it into the Stack Panel.
var nextButton = new Button();
nextButton.Name = "NextBtn";
next.Children.Add(nextButton);
then tried to find it with
this.FindName("NextBtn")
and it always comes null.
What am I doing wrong?

Use RegisterName instead of nextButton.Name = "NextBtn";
var nextButton = new Button();
RegisterName("NextBtn", nextButton); // <-- here
next.Children.Add(nextButton);
You can then find it with:
this.FindName("NextBtn")

As Farhad Jabiyev mentioned I created duplicate.
As related question (FindName returning null) explaines
from this page https://msdn.microsoft.com/en-us/library/ms746659.aspx
Any additions to the element tree after initial loading and processing
must call the appropriate implementation of RegisterName for the class
that defines the XAML namescope. Otherwise, the added object cannot be
referenced by name through methods such as FindName. Merely setting a
Name property (or x:Name Attribute) does not register that name into
any XAML namescope.

You could find the button manually, for example:
foreach (var child in next.Children)
{
if (child is Button && (child as Button).Name == "NextBtn")
;// do what you want with this child
}
Or:
var btn = next.Children.OfType<Button>().FirstOrDefault(q => q.Name == "NextBtn");
if (btn != null)
;// do what you want

Related

How can I count up the name of a Button with a Variable

I'm trying to make a battleship game in which the game field buttons all start with the letter A and then a number. Now I want to count up the numbers but still be able to do basic button functions like BackgroundImage.
What I'm doing now is just create a sting which adds the A with the number I receive from the function.
string btnr = "A";
btnr = btnr + Convert.ToString(nr);
string btnr = "A";
btnr = btnr + Convert.ToString(nr);
btnr.BackgroundImage = Image.FromFile(#"T:\E\_AUSTAUSCH\Com.Menu_OpenSurce\Battleship\Bilder\ACC_5_W.png");
This should change the Background image of the Button with the "nr" xx but I already get an error message saying:
Error 3 "string" contains no definition for "BackgroundImage", and no
extension method "BackgroundImage" could be found that accepts a first
argument of type "string". (Is there no Using directive or assembly
reference?)
Assuming WinForms, you can use Controls.Find to get a reference to the Button, no matter how deeply nested it is:
string btnName = "A" + nr.ToString();
Control ctl = this.Controls.Find(btnName, true).FirstOrDefault();
if (ctl != null && ctl is Button)
{
Button btn = (Button)ctl;
btn.BackgroundImage = Image.FromFile(#"T:\E\_AUSTAUSCH\Com.Menu_OpenSurce\Battleship\Bilder\ACC_5_W.png");
}
You are getting the button name. But you need to reference to the button object. To do this, you can use the controls property to select the button by name:
Please note that this example assumes that the button exists and the control is of type Button. Update: also assumes that the buttons are inmediate childs of the form
var button = (Button)Controls[btnr];
button.BackgroundImage =
Image.FromFile(#"T:\E\_AUSTAUSCH\Com.Menu_OpenSurce\Battleship\Bilder\ACC_5_W.png");

How to get the parents name of a control

Is it possible to get the parent name of a control ? ex. I have a panel and there is a button inside it.
what I want is if i click the button i'll get the name of the panel.
Well if the button is inside the panel (which is a container), you could get it using:
var panelName = myBtn.Parent.Name;
Useful links:
Control.Parent which returns a Control object.
As per the comment of DaveShaw, if you're working with events you could get the parent from the sender argument:
var myBtn = sender as Button;
var panelName = myBtn.Parent.Name;

Edit a button by its given name

I am generating x amount of buttons and I give all of them a unique name.
After all those are generated, I want to edit one of them without regenerating them so I was wondering if I could get a component by its name?
I am using WinForms
Yes:
Control myControl = Controls.Find("textBox1");
Now, beware that you have to do proper casting hen found, because Find returns a control.
You can use Controls property of your form (or some container control on your form). With LINQ you can select buttons and then find first button with required name:
var button1 = Controls.OfType<Button>().FirstOrDefault(b => b.Name == "button1");
Or if you want to search child controls recursively
var button1 = Controls.Find("button1", true)
.OfType<Button>()
.FirstOrDefault();
Without LINQ you can use method Find(string key, bool searchAllChildren) of ControlCollection:
Control[] controls = Controls.Find("button1", true);
if (controls.Length > 0)
{
Button button1 = controls[0] as Button;
}
Button btn1 = (Button)(Controls.Find("btnName"));
This will get the required button and will save the button attributes into a new Button btn1
After all those are generated, I want to edit one of them without
regenerating them so I was wondering if I could get a component by its
name?
var myButton = Controls.Find("buttonName", true).FirstOrDefault(); //Gets control by name
if(myButton != null)
{
if (myButton.GetType() == typeof(Button)) //Check if selected control is of type Button
{
//Edit button here...
}
else
{
//Control isn't a button
}
}
else
{
//Control not found.
}
Make sure you add a reference to: linq.

FindControl returns null

I am working on a solution in C# and ASP.NET 4.0 I am trying to get the value of a radiobutton from my page that was dynamically created based on some database information.
Here is what gets generated in the page source:
<td>
<input id="masterMain_3Answer_0" type="radio" name="ctl00$masterMain$3Answer"
value="Y" onclick="return answeredyes(3);" />
<label for="masterMain_3Answer_0">Y</label>
</td>
<td>
<input id="masterMain_3Answer_1" type="radio" name="ctl00$masterMain$3Answer"
value="N" onclick="return answeredno(3,'desc');" />
<label for="masterMain_3Answer_1">N</label>
</td>
Inside the OnClick function of my submit button I want to gather wether Y or N has been selected based on the user's input.
Here is what I have written so far:
RadioButton _rbAnswer = new RadioButton();
RadioButtonList _rbList = new RadioButtonList();
ContentPlaceHolder cp = (ContentPlaceHolder)Master.FindControl("masterMain");
_rbAnswer = (RadioButton)Master.FindControl("masterMain_3Answer_0");
HtmlInputRadioButton rb = (HtmlInputRadioButton)Master.FindControl("masterMain_3Answer_0");
_rbAnswer = (RadioButton)cp.FindControl("masterMain_3Answer_0");
_rbList = (RadioButtonList)cp.FindControl("masterMain_3Answer_0");
I am able to get the ContentPlaceHolder without any issues but the rest of the objects are null after it attempts to get the . I have also attempted removing the "masterMain_" but still doesn't want to find the controls.
Here is the code in which the individual radiobuttonlists are added
TableRow _tempRow = new TableRow();
TableCell _cellOK = new TableCell();
RadioButtonList _rbList = new RadioButtonList();
_rbList.ID = r[0].ToString()+"Answer";
_rbList.RepeatDirection = RepeatDirection.Horizontal;
//add options for yes or no
ListItem _liOk = new ListItem();
_liOk.Value = "Y";
ListItem _linotOk = new ListItem();
_linotOk.Value = "N";
_rbList.Items.Add(_linotOk);
//add cell to row
_rbList.Items.Add(_liOk);
_cellOK.Controls.Add(_rbList);
_tempRow.Cells.Add(_cellOK);
//add the row to the table
stdtable.Rows.Add(_tempRow);
To be able to quickly find dynamically created controls, add a dictionary to your page class:
private Dictionary<string, Control> fDynamicControls = new Dictionary<string, Control>();
then when a new control is created in code and its ID is assigned:
fDynamicControls.Add(newControl.ID, newControl);
and when you need control's reference:
Control c = fDynamicControls["controlIdThatYouKnow"];
When using FindControl don't use the id that's generated by the page. Use the ID that you specified inthe aspx.
If this is inside a Repeateror another DataBound control, you have to first find the current record. (GridViewRow or RepeaterItem) first, an use that item's .FindControl function.
See this (different - not duplicate) question to see a code example of how to do it: How to find control with in repeater on button click event and repeater is placed with in gridview in asp.net C#
When you create dynamic controller give specific ids for them. This facilitate to generate controls with our own id. therefore then we can access the controls with this id.
And also use OnInit life cycle event to generate dynamic controllers, this is the best place to generate them.
RadioButton _rbAnswer = new RadioButton();
_rbAnswer.ID="ranswerid";
Given your update, you'll find that your control heirarchy is fairly deep. You have a RadioButtonList inside a cell inside a row inside a table ...
FindControl is a method that needs to be called on a specific object and can only find objects that are actual children of that object. In this case, you either need to build a recursive method or go directly to the control in question. Since so many of these controls are generated dynamically, you'll have no real way of accessing them directly so building the recursive function may be simplest. However, on very large pages this method can be very resource consuming:
public static WebUserControl FindControlRecursive(this WebUserControl source, string name)
{
if (source.ID.Equals(name, StringComparison.Ordinal))
return source;
if (!source.Controls.Any()) return null;
if (source.Controls.Any(x => x.ID.Equals(name, StringComparison.Ordinal))
return source.FindControl(name);
WebUserControl result = null;
// If it falls through to this point then it
// didn't find it at the current level
foreach(WebUserControl ctrl in source.Controls)
{
result = ctrl.FindControlRecursive(name);
if (result != null)
return result;
}
// If it falls through to this point it didn't find it
return null;
}
This is an extension method that would allow you to call this on your ContentPlaceHolder control:
var _cp = (ContentPlaceHolder)Master.FindControl("masterMain");
RadioButtonList _rbList = _cp.FindControlRecursive("3Answer");
if (_rbList != null)
// ... Found it
Note: Treat the above as psuedo-code. It has not be implemented by me anywhere so may (likely) require tweaking to behave exactly right.

Get values from dynamic controls with c#?

I created a few radiobuttonlist controls on my project, they're created every time the page is loaded, i want to get the value of the radiobutton that the user has selected, but since my radiobuttons were created dynamically, i don't know how to acces to their values nor how to create their event handlers. Is there a way to assign a name or id to the control when i create it?
i hope you can help me.
I create a seires of radiobuttlist on the page_load event, with the text and their values been pulled out of a database. now, the user has to choose one of the options from that radiobuttlist and i want to get the value of the radiobutton the user checked. how do i do that if i don't know the name nor the id of the radiobuttlist since they're created dynamically.
this is what i've got:
for (int i = 3; i < numfields; i++) {
if (dr[i].ToString() != "" && dr[i] != null){
r.Items.Add(new ListItem(dr[i].ToString(), dr[i].ToString()));
//r.SelectedIndexChanged += new EventHandler(rowSelectedIndex);
}
}
so basically i use my datareader to loop through the data in the database, if the value from the field isn't empty or null, then i add an item to the radiobuttlist called "r"
i tried to create an eventhandler for that too, but since i have never worked with them i really don't know what to do. :(
I'm so sorry if i seem way too pathetic.
Taking a quick look at your code:
for (int i = 3; i < numfields; i++) {
if (dr[i].ToString() != "" && dr[i] != null){
r.Items.Add(new ListItem(dr[i].ToString(), dr[i].ToString()));
//r.SelectedIndexChanged += new EventHandler(rowSelectedIndex);
}
}
The most obvious thing that jumps out is your if statement. You should first check for null:
if (dr[i] != null && dr[i].ToString() != ""){
As if dr[i] is null, you'll get an exception (as you'll be trying to call the ToString() method on a null object.
If the contents of dr are always going to be strings, you might consider writing:
if(!String.IsNullOrEmpty(dr[i]){
I also note you start your indexing at 3 - is this because you want to skip the first 3 fields?
Wherever you create your variable, 'r', you can set the name and ID properties. You can use the ID property to look for the control on PostBack. So if you created your radiolist like so:
RadioButtonList r = new RadioButtonList();
r.Id = "MyRadioButtonList";
r.SelectedIndexChanged += MyRadioButton_SelectedIndexChanged;
Which would point at the following event handler:
private void MyRadioButton_SelectedIndexChanged(Object sender, EventArgs e) {
... Do Stuff ...
}
There are several ways of finding your control when you post back; you can look in the Request.Forms collection for a control matching the name of the control you submitted, or, more appropriately, you can use the FindControl method with the ID you gave the control. See C#, FindControl for a post with a method (by Jeff Atwood!) that will search the entire hierarchy of controls for your control.
When you add a dynamic control is important, too. If you add it too late in the page lifecycle then it will not be available on PostBack. See http://support.microsoft.com/kb/317515 for more details on just when to add a control. There are plenty of resources for Dynamic ASP.Net controls around too.
You could put your RadioButton into a list as you create them. This is also when you want to add your handlers.
RadioButton rb;
for (int i = 1; i < 5; i++)
{
rb = new RadioButton();
rb.AutoSize = true;
rb.Location = new System.Drawing.Point(25, (i*25) + 25);
rb.Name = "radioButton" + i.ToString();
rb.Text = "radioButton" + i.ToString();
//Add some event handler?
this.Controls.Add(rb);
lstRadioButton.Add(rb);
}
Whenever you want to know which one is selected you can do a foreach loop of your list and look if your RadioButton is checked.
foreach (RadioButton rButton in lstRadioButton)
{
if (rButton.Checked == true)
{
//Do something
}
}
You are maybe searching for TagName property if the programmatic name isn't enough for you.
The problem is that you are creating the controls in page_load. In order for their values to be posted back into the controls correctly, you must move this creation into the page_init method and recreate them every time.
Then, in page_load, you can access the values in the controls correctly. If you give them IDs using a consistent naming convention, you will be able to find them using the FindControl method or, in page_init, you can store them in a collection at the page or user control level.

Categories

Resources