Asp.NET server control events not firing - c#

Thanks for all who reads. I have a code issue that has been discussed many times on stackoverflow, but I can't make the provided solutions work.
It's about server control that contain other controls and I can't fire their events.
My issue is simple, i need to add any numbers ok LinButton into my server control. this is my code:
protected override void CreateChildControls()
{
for (int i = 0; i < IndiceValue; i++)
{
LinkButton imageTemp = new LinkButton() { CommandName = String.Format("{1}_{0}", CommandNames, i), Text = i.ToString(), ID = Guid.NewGuid().ToString()};
imageTemp.Click += ImageTempOnClick;
this.Controls.Add(imageTemp);
}
base.CreateChildControls();
}
I have a custom event in my control:
public delegate void IndiceFiabiliteCommand(object sender, IndiceFiabiliteCommandEventArg e);
public event IndiceFiabiliteCommand Command;
And theorically, when any of the LinkButton is clicked, I want the user to be warn that any of the LinkButton has been clicked. I give him all the needed infos but i don't think this part is the problem.
Last thing to know is that I implement INamingContainer and I tried to implement both, IPostBackDataHandler and IPostBackEventHandler but it didn't worked.
I hope it's understandable enough
thanks!

The problem is ID = Guid.NewGuid().ToString()
You cannot have dynamically created control with dynamic id. Change the code to
... i.ToString(), ID = i.ToString()
Basically, dynamic control's ID must be same as the ID originally created.
Otherwise, new control is created on every post-back, and it cannot find the control which causes the post-back.
FYI: if you need to catch an event, I would like to suggest to use CompositeControl which already have INamingContainer.
Note: it is just what I found based on your code; it might be other issue too.

Related

Is there any way that I could "array" a group of pictureBox to use in a for statement? [duplicate]

Has C# indexed control arrays or not? I would like to put a "button array" for example with 5 buttons which use just one event handler which handles the index of all this 5 controls (like VB6 does). Else I have to write for each of these 5 buttons one extra event handler. And if I have 100 buttons, I need 100 event handlers? I mean something like that:
TextBox1[i].Text="Example";
It could make coding definitely easier for me to work with control arrays. Now I have seen, that C# at least has no visible array functionality on user controls and no "index" property on the user controls. So I guess C# has no control arrays, or I must each element call by known name.
Instead of giving 100 TextBoxes in a for loop 100 incrementing values, I have to write:
TextBox1.Text = Value1;
TextBox2.Text = Value2;
...
...
TextBox100.Text = Value100;
A lot of more work + all these 100 event handlers each for one additional TextBox extra.
I know I'm a little late to this party, but this solution will work:
Make a global array:
TextBox[] myTextBox;
Then in your object's constructor, after the call to
InitializeComponent();
initialize your array:
myTextBox = new TextBox[] {TextBox1, TextBox2, ... };
Now you can iterate your array of controls:
for(int i = 0; i < myTextBox.Length; i++)
myTextBox[i].Text = "OMG IT WORKS!!!";
I hope this helps!
Pete
As I mentioned in comment to a solution by HatSoft, C# Winforms does not allow you to create control arrays like old VB6 allowed us. The nearest I think we can get to is what HatSoft and Bert Evans in their posts have shown.
One thing that I hope would satisfy your requirement is the event handler, you get a common event handler and in the event handler when you typecast the "sender" you get the control directly just like you would in VB6
C#
TextBox textBox = sender as TextBox;
VB6
TextBox textBox = TextBox1[i];
So the only trouble you might have is wiring those 100 TextBoxes to a single event handler, if you are not creating the controls dynamically through code rather creating it manually at design time then all one can suggest is group them in a container like say Panel. Then on Form Load wire them all up to a single event handler like this:
foreach (Control control in myTextBoxPanel.Controls)
{
if(control is TextBox)
control.TextChanged += new EventHandler(control_TextChanged);
}
Just create one handler and point all the buttons to it.
var ButtonHandler = (sender, args) => {
var clicked = (Button)sender;
if (clicked.Text == "whatever")
//do stuff
else
//do other stuff
};
button1.Click += ButtonHandler;
button2.Click += ButtonHandler;
Alternatively, if you are creating controls in code, you could use one of the techniques specified in this answer.
Instead of giving 100 TextBoxes in a for loop 100 incrementing values, I have to write:
for(int i = 0; i <100; i++)
{
TextBox t = new TextBox(){ Id = "txt_" + i, Value = "txt_" + i};
t.TextChanged += new System.EventHandler(this.textBox_Textchanged);
Page.Controls.Add(t);
}
//and for event on TextChanged
private void textBox_Textchanged(object sender, EventArgs e)
{
TextBox textBox = sender as TextBox;
if (textBox != null)
{
////
}
}
Another thing to note: if you really need to edit 100 strings on one form, you should probably think about whether 100 text boxes is really the best way to do it. Perhaps a ListView, DataGridView, or PropertyGrid would be better suited.
This applies almost any time you think you need a huge array of controls.
If you are working with Web Forms and not MVC, you can acces a collection of controls on the page as shown in Using the Controls Collection in an ASP.NET Web Page. Essentially the controls collection is a tree with the page hosting the first level of child controls and some items having children of their own. See How to: Locate the Web Forms Controls on a Page by Walking the Controls Collection for an example of how to follow the tree.
Also, see How to: Add Controls to an ASP.NET Web Page Programmatically.
You can use the same event handler for multiple items as long as the signature required is the same.
For Windows Forms this is nearly identical since they're based on similar architectural models, but you'll want Control.Controls Property and How to: Add Controls to Windows Forms.
Keeping it simple:
TextBox[] keybox = new TextBox[16]; //create an array
for (int i=0; i<16; i++)
{
keybox[i] = new TextBox(); //initialize (create storage for elements)
keybox[i].Tag = i; //Tag prop = index (not available at design time)
keybox[i].KeyDown += keybox_down; //define event handler for array
}
private void keybox_down(object sender, KeyEventArgs e)
{
int index = (int)((TextBox)sender).Tag //get index of element that fired event
...
}

ASP.Net Page Lifecycle and dynamic controls

I'm am a little bit stuck in the ASP.Net's page lifecycle. This is my first ASP.Net project after many years of doing React so I might be missing something;)
Simplified code:
protected void Page_Load(object sender, EventArgs e)
{
BuildView();
}
private void BuildView()
{
switch (pageViewMode.Value)
{
case "Overview": BuildOverview(); break;
case "Runs": BuildRunsOverview(); break;
}
}
private void BuildOverview()
{
var tilesContainer = new TilesContainer();
tilesContainer.OnTileClicked += (InfoTile targetTile) =>
{
pageViewMode.Value = targetTile.Value;
BuildView();
};
rootElement.Controls.Add(tilesContainer);
}
The problem is that the "OnTileClicked" event works only on the first load and not after the postback. I believe it has something to do with the page lifecycle and registering the events after the Control events ( https://learn.microsoft.com/en-us/previous-versions/aspnet/ms178472(v=vs.100)?redirectedfrom=MSDN ).
If it is really the case, how do I then dynamically build pages from the code behind? Should I really create all the controls ( BuildOverview() and BuildRunsOverview()) and then conditionally show or hide them?
'Should I really create all the controls ( BuildOverview() and BuildRunsOverview()) and then conditionally show or hide them?'
Answer is: yes.
You don't dynamically build pages from code behind - at least its not that well supported in asp.net pages.
In your case you need the TilesContainer on every postback and attach the event handler to it, else the event won't be called. So it would be easier to put all your controls in the markup (.aspx) and just set them to Visible = false/true depending on your code. Controls you set to Visible = false won't be rendered on the client side, so at least no overhead there.
If you use custom-controls (I assume your TilesContainer is a custom-control), then you need to implement the Visible-property the right way, e.g. if your TilesContainers main control is a Panel, override Visible and set the value there:
public override bool Visible
{
get { return base.Visible; }
// set all neccessary controls visibility here
set { this.pnlMain.Visible = base.Visible = value; }
}

Reading __EVENTTARGET causes event is not called

I want to use information on which control was clicked for setting up the page. I use this to set up a sortable table in code. I found through this forum that I can use Request.Form.Get("__EVENTTARGET") for that. However, as soon as I do something with that parameter, the callback function is no longer called. Is this expected behavior or am I making a mistake?
Here some snippets of my code. The code in Page_Load() is:
string sortRequest = Request.Form.Get("__EVENTTARGET");
bool isCurrentField = false;
if (sortRequest != null) isCurrentField = sortRequest.Contains(header.Field);
if (!isCurrentField)
{
// Add a hyperlink for sorting to the cell
LinkButton newLink = new LinkButton();
newLink.Text = header.Title;
newLink.Font.Bold = true;
newLink.ID = "link" + header.Field;
newLink.CommandName = "Sort";
newLink.CommandArgument = header.Field;
newLink.Command += new CommandEventHandler(LinkButton_Command);
hdrCell.Controls.Add(newLink);
}
else
{
hdrCell.Text = header.Title;
hdrCell.Font.Bold = true;
}
My callback:
public void LinkButton_Command(Object sender, CommandEventArgs e)
{
_sortOrder = e.CommandArgument.ToString();
}
I have also tried it with copying the sortRequest into a temporary variable, but that doesn't make a difference. As soon as I comment out the line if (sortRequest != null) isCurrentField = sortRequest.Contains(header.Field);, the callback is called again.
There is a fault in your logic. You have a dynamically created control LinkButton with LinkButton_Command event handler connected to it. For the server-side event to fire on postback, the control must be present in the page control tree. This means the dynamic LinkButton must be created, configured and added to hdrCell.Controls always, regardless of sortRequest value. Only then will it be able to pick up the fact that it was clicked from the Request and fire its Command event.

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.

Multiple instances of server control attached programmatically not appearing?

In the code behind of my page I want to attach a label in multiple places. To achieve this and avoid creating mutliple instances of the same label I've tried:
Label lblNone = new Label();
lblNone.Text = "<br/> None. <br/>";
Master.mainContent.Controls.Add(lblNone);
Master.mainContent.Controls.Add(lblNone);
Master.mainContent.Controls.Add(lblNone);
For some reason I only see 1 instance of the "None." on my page?
Why is this?
You have no option.. you need to create one instance of Label for each control you want to see in the screen.
This is because of the behavior of the ControlCollection class.
it will not allow multiple adds of the same "reference".
When you add a control to one ControlCollection it is automatically removed from the previous so, even if you were adding your label to different ControlCollections it wouldn't work.
PS: By ControlCollection I mean the type of the property Master.mainContent.Controls
You might find it easier to create a method for this as so: -
protected void Page_Load(object sender, EventArgs e)
{
this.Controls.Add(CreateLiteral("text"));
this.Controls.Add(CreateLiteral("text"));
this.Controls.Add(CreateLiteral("text"));
}
private Literal CreateLiteral(string Content)
{
Literal L = new Literal();
L.Text = Content;
return L;
}
Thanks,
Phil.

Categories

Resources