This is my code :
private string[] MesiSelezionati;
protected void Page_Load(object sender, EventArgs e)
{
MesiSelezionati = new string[] { "2", "4" };
UpdateMesi();
}
override protected void OnInit(EventArgs e)
{
for (int i = 1; i <= 12; i++)
{
HtmlGenericControl meseItem = new HtmlGenericControl("a") { InnerHtml = "mese" };
meseItem.Attributes.Add("href", "javascript:void(0);");
HiddenField hf = new HiddenField();
hf.Value = "0";
hf.ID = "idMese_" + i.ToString();
meseItem.Controls.Add(hf);
panelMesi.Controls.Add(meseItem);
}
base.OnInit(e);
}
private void UpdateMesi()
{
foreach (HtmlGenericControl a in panelMesi.Controls.OfType<HtmlGenericControl>())
{
HiddenField hf = a.Controls.OfType<HiddenField>().LastOrDefault();
if (MesiSelezionati.Contains(hf.ID.Split('_').LastOrDefault()))
{
hf.Value = "1";
a.Attributes.Add("class", "box-ricerca-avanzata-item link-box selected");
}
}
}
When I call the page, all is ok! The problem is when I call the same page (so, postback) thanks to a asp:LinkButton. I get a System.NullReferenceException on if (MesiSelezionati.Contains(hf.ID.Split('_').LastOrDefault())).
Seems that the HiddenField of the 2° and 4° link (which corrispond to the position at MesiSelezionati = new string[] { "2", "4" };) are null. Why? And how can I fix it?
EDIT : code for Mark M
HtmlGenericControl optionBox = new HtmlGenericControl("div");
optionBox.Attributes["class"] = "option-box";
HtmlGenericControl optionBoxItem = new HtmlGenericControl("a") { InnerHtml = " " };
optionBoxItem.Attributes.Add("href", "javascript:void(0);");
optionBoxItem.Attributes.Add("class", "option-box-item");
HtmlGenericControl optionBoxTesto = new HtmlGenericControl("a") { InnerText = Categoria.Categoria };
optionBoxTesto.Attributes.Add("href", "javascript:void(0);");
optionBoxTesto.Attributes.Add("class", "option-box-testo");
HiddenField hf = new HiddenField();
hf.Value = "0";
hf.ID = "categoria_" + Categoria.UniqueID;
optionBox.Controls.Add(optionBoxItem);
optionBox.Controls.Add(optionBoxTesto);
optionBox.Controls.Add(hf);
panelCategorieGuida.Controls.Add(optionBox);
You can update hidden fields on postback, just not before Load. When executing OnInit, the controls have not been populated using the request & view state values. Your updates are being overwritten.
EDIT: I found the root cause of your issue & learned something in the process.
You set the InnerHtml property of the anchor tag (InnerHtml = "mese") in the OnInit method. Under the covers this assignment is ViewState["innerhtml"] = "mese".
You assign a css class to the anchor after ViewState tracking has begun, so the ViewState restoration machinery will apply to this control on postback.
When you postback the anchor tags with added css classes will be subject to HtmlContainerControl.LoadViewState (which occurs between InitComplete and PreLoad). If the LoadViewState method detects that ViewState["innerhtml"] has a value it wipes out all of the control's child controls (calling Controls.Clear()) and creates a LiteralControl to contain the innerhtml value, adding it as the sole child control.
Basically this means that you cannot set both the InnerHtml property and add any controls to a descendant of HtmlContainerControl if that control will ever be subject to ViewState tracking.
To fix your example; instead of setting InnerHtml to add the link text, create a LiteralControl with the desired text and add it to the anchor's child control collection.
is your link button in some separate panel control? Can it be the case that you are doing partial postback, with AJAX? Sorry for answering with the question.
Related
I'm trying to call events of dynamically created buttons sending parameters, but when I click nothing happens, just Post Back the page.
public void adicionarComanda()
{
List<Comanda> lc = ControllerComanda.getComanda();
foreach (Comanda comanda in lc)
{
Button bt = new Button();
bt.Text = comanda.nome_Pessoa;
bt.CssClass = "botoes";
bt.Click += btnNome1_Click;
bt.CommandArgument = comanda.nome_Pessoa;
HtmlGenericControl li = new HtmlGenericControl("li");
li.Controls.Add(bt);
ulBotoes.Controls.Add(li);
}
}
And the Event
protected void btnNome1_Click(object sender, EventArgs e)
{
string nomePessoa = (sender as Button).CommandArgument;
Session["currentUser"] = nomePessoa.ToString();
Response.Redirect("~/Mobile/Pages/produtosCategoria.aspx");
}
But nothing Happens when I click the button, just PostBack the page. How can I fix this problem?
Thank you guys
You need to re-render all dynamically generated controls on every postback. I suggest creating a method that generates the these controls then call that method on every postback in Page_Load.
Have you thought about maybe passing "currentuser" as a parameter? bt.Attributes.Add("onclick", "javascript:redirect('~/Mobile/Pages/produtosCategoria.aspx?name=comanda.nome_Pessoa')";
Instead of defining click function you can use another approach - PostBackUrl.
public void adicionarComanda()
{
List<Comanda> lc = ControllerComanda.getComanda();
foreach (Comanda comanda in lc)
{
Button bt = new Button();
bt.Text = comanda.nome_Pessoa;
bt.CssClass = "botoes";
bt.PostBackUrl = String.Format("~/Mobile/Pages/produtosCategoria.aspx?user={0}", comanda.nome_Pessoa);
HtmlGenericControl li = new HtmlGenericControl("li");
li.Controls.Add(bt);
ulBotoes.Controls.Add(li);
}
}
Then in the redirected page you can use Request.QueryString["user"] , and use it as required.
I have a class derived from WebControls.TableCell.
When the Text property is set, I call a method that dynamically adds asp:Panels and asp:LiteralControls to the Cell. I want to reference these controls in Javascript, so naturally I tried using the ClientId of the panels in my JS functions. However, these controls have no ClientId set (the string is empty). Why is this? How do I force the ClientIds to be set?
As a temporary solution, I set the ClientIDMode to "static" and created the IDs on my own, but this is not satisfactory because it's hard to reference those IDs in JS. Why? If you assign, for example, "12345" to one control, it gets changed on client side to something like "MainContent_123456". This is bad because the "MainContent" part is not fixed; thus I never know for sure what the real Id on the client side will be. Currently, I can get the control with jQuery using $ctrl = $('[id$='12345']');, but this is dirty because it would get any control that has '123456' in its id.
So, back to the original question: how do I get my ClientIds set automatically for my panels in my custom TableCells?
Edit: Code added
protected void Page_Load(object sender, EventArgs e)
{
this.ClientIDMode = System.Web.UI.ClientIDMode.Static;
}
Code in the method that adds the controls to the custom TableCell:
Panel remainingTextPanel = new Panel();
remainingTextPanel.ID = Guid.NewGuid().ToString();
remainingTextPanel.Style["display"] = "none";
LiteralControl remainingText = new LiteralControl(myText.Substring(initialStringLength, myText.Length - initialStringLength));
remainingTextPanel.Controls.Add(remainingText);
this.Controls.Add(remainingTextPanel);
Panel linkBtnPanel = new Panel();
LinkButton lnkBtn = new LinkButton() {Text = "...", OnClientClick = "toggleDynamicText('" + remainingTextPanel.ID + "'); return false;" };
lnkBtn.Font.Bold = true;
linkBtnPanel.Controls.Add(lnkBtn);
this.Controls.Add(linkBtnPanel);
And the JS Code:
function toggleDynamicText(id) {
$ctrl = $('[id$=' + id + ']');
$(document).ready(function () {
$ctrl.toggle(1000);
});
}
Without seeing any code it's difficult to say what's going on but to access your controls using jQuery you can do the following:
$("#<%=myElement.ClientID%>")
This way it doesn't matter what .NET assigns as the ID.
I get that error when trying to generate a number of buttons programmatically. I have no ctl02.. Why do i get that mistake?
Button pgs = new Button();//Create New Topic
pgs.Width = 20;
pgs.Command += obtainTopicsPerPage_Click;
pgs.CommandName = tPage.ToString();
pgs.Text = tPage.ToString();
btns.Add(tPage.ToString());
buttons.Add(pgs);
I create a few buttons and loop through the list (buttons). Then i get that mistake :(. ... why?
Full design:
int maximumTopicPages;
int tPage;
int questionNumber=1;
Dictionary<string, List<DisplayAllQuestionsTable>> tPages;
List<Button> buttons = new List<Button>();
protected void Answer_Click(object sender, EventArgs e)
{
ViewState["SeekPressed"] = "pressed";
tPages = new Dictionary<string, List<DisplayAllQuestionsTable>>();
string subTopic = SubTopicDropDownList.SelectedItem.Value;
List<DisplayAllQuestionsTable> threadsByTopic = new List<DisplayAllQuestionsTable>();
List<string> btns = new List<string>();
foreach (var topicKeys in postsByTopic)
{
if (topicKeys.Key == subTopic)
{
foreach (var item in postsByTopic[topicKeys.Key])
{
questionNumber++;
maximumTopicPages++;
threadsByTopic.Add(item);//Adds All DisplayAllTables objects
//if there are 20 add a button.
if (maximumTopicPages == 20)
{
tPages.Add(tPage++.ToString(), threadsByTopic);//Add a number to the page each time, with a DisplayTable object
//new Button
Button pgs = new Button();//Create New Topic
pgs.Width = 20;
pgs.Command += obtainTopicsPerPage_Click;
pgs.CommandName = tPage.ToString();
pgs.Text = tPage.ToString();
btns.Add(tPage.ToString());
buttons.Add(pgs);
maximumTopicPages = 0;
threadsByTopic.Clear();
}
}//number of questions per page
if (!tPages.ContainsKey((questionNumber / 20).ToString()))
{
tPages.Add((questionNumber / 20).ToString(), threadsByTopic);//If A button is missing add it.
}
}
Way the buttons are added to the table:
void MyButtonTable()
{
TableRow myTableRow = new TableRow();
HtmlForm form = new HtmlForm();
form.Attributes.Add("runat", "server");
Page.Controls.Add(form);
foreach (var item in buttons)
{
TableCell myTableCell = new TableCell();
form.Controls.Add(item);
myTableCell.Controls.Add(item);
myTableRow.Cells.Add(myTableCell);
}
Table2.Rows.Add(myTableRow);
Page.Controls.Add(Table2);
}
Are you adding your buttons to the Page afterwards?
Also, if you do not specify an ID to your buttons, they will be given one automatically in the form of ctlXXX
What is in the .aspx file? Specifically, what is the 'buttons' control? My guess is, it is a placeholder or panel or something similar. In that case, you need to add this to your .aspx file:
...
<body>
<form runat="server">
...
</form>
</body>
...
That should fix it.
ASP.NET needs to have the <form> tag managed by the server in order to use server side controls on your page. If your page already has a <form> tag on it somewhere, you can just add runat="server" to that tag and it will fix it. (That assumes the 'buttons' control that you're trying to add the dynamically created button into -- the placeholder or panel or whatever -- is itself between the <form>...</form> tags.)
Its working....
Please add your new button control into from
protected void btnsubmit_Click(object sender, EventArgs e)
{
Button objButton = new Button();
objButton.Text = "New Button";
objButton.ID = "randomButton";
form1.Controls.Add(objButton);
}
Here form1 -> form name available into .aspx file and objButton is button object.
You have to check if "buttons" (I think is a placeholder) is inside a div or a tag with runat="server"
update
If I understand you can try something like this:
HtmlForm form = new HtmlForm();
form.Attributes.Add("runat", "server");
form.Controls.Add(buttons);
Page.Controls.Add(form);
(untested)
I have dynamically created hidden input controls in a C# code-behind file, and then populated their values with JavaScript. I now want to access these variables in C#.
Firebug shows that the values do change with JavaScript, but I'm getting the original values back in the code behind. Any insight would be much appreciated.
JavaScript:
function injectVariables(){
var hidden = document.getElementById("point1");
hidden.value = 55;
var hidden2 = document.getElementById("point2");
hidden2.value = 55;
var hidden3 = document.getElementById("point3");
hidden3.value = 55;
alert("values changed");
}
ASPX:
<asp:Button OnClick="Update_PlanRisks" OnClientClick="injectVariables()" Text="updatePlanRisks" runat="server" />
C#:
protected override void CreateChildControls()
{
base.CreateChildControls();
int planId = Convert.ToInt32(Request.QueryString.Get("plan"));
planRisks = wsAccess.GetPlanRiskByPlanId(planId);
foreach (PlanRisk pr in planRisks)
{
HtmlInputHidden hiddenField = new HtmlInputHidden();
hiddenField.ID= "point" + pr.Id;
hiddenField.Name = "point" + pr.Id;
hiddenField.Value = Convert.ToString(pr.Severity);
this.Controls.Add(hiddenField);
}
}
protected void Update_PlanRisks(object sender, EventArgs e)
{
foreach (PlanRisk pr in planRisks)
{
int planRiskId = pr.Id;
string planRiskName = "point" + pr.Id;
HtmlInputHidden hiddenControl = (HtmlInputHidden) FindControl(planRiskName);
string val = hiddenControl.Value;
}
}
This is one way to get the value from the request...
string point1 = Request.Form["point1"];
In CreateChildControls you are explicitly setting the value of the hidden field(s). CreateChildControls runs each time during the page lifecycle (potentially multiple times), when you click submit, the page posts back and runs through the entire lifecycle again - including CreateChildControls - before running the click handler Update_PlanRisks.
The simplest way to avoid this problem is to check if you are in PostBack before setting the value of your hidden fields:
if(!IsPostBack)
{
hiddenField.Value = Convert.ToString(pr.Severity);
}
I have some link buttons in which I am dynamically adding a style to it. I am doing the following in a method:
LinkButton lb = new LinkButton();
lb.Style["font-weight"] = "bold";
When the another link is clicked, it should unbold the link button that is bold and bold the currently clicked one, so in the method that is doing this, I have tried:
lb.Style["font-weight"] = "none";
The above does not work though, the previously selected link stays bold.
I just realized the possible problem. I am creating multiple links and what it looks like is that since all the links are named lb, it never removes the bold. I am trying to think of a way for it to remember the previously selected link and to only unbold that one.
Can I suggest an alternative approach?
Set a CSS Style:
.selected { font-style: bold; }
When a link is clicked set that link's CSS class to "selected" and the others to "";
EDIT: To accommodate for existing Css Class
const string MY_CLASS = "links";
lb1.CssClass = MY_CLASS + " selected"; // selected
lb.CssClass = MY_CLASS; // not selected
You can quickly get into trouble when defining inline styles, in that they're difficult to overwrite.
EDIT 2:
Something like this code should work. You may have to loop through all the LinkButtons in the list, but I don't think so. I'd just turn off ViewState on the LinkButtons.
// container for links. so you can reference them
// outside of the creation method if you wish. I'd probably call this method in the
// Page_Init Event.
List<LinkButton> listOfLinks = new List<LinkButton>();
const string MY_LB_CLASS = "linkButton"; // generic lb class
private void createSomeLinks() {
for (int i = 0; i < 10; i++) {
// create 10 links.
LinkButton lb = new LinkButton()
{
ID = "lb" + i,
CssClass = MY_LB_CLASS
};
lb.Click += new EventHandler(lb_Click); // Add the click event
}
// You can bind the List of LinkButtons here, or do something with them.
}
void lb_Click(Object sender, EventArgs e) {
LinkButton lb = sender as LinkButton; // cast the sender as LinkButton
if (lb != null) {
// Make the link you clicked selected.
lb.CssClass = MY_LB_CLASS + " selected";
}
}
Try lb.Style.Remove("font-weight"). I didn't test it, but you can try it out.
Alternatively, have you tried settings the Font.Bold property?
lb.Font.Bold = true;
Try ListBox1.Attributes.Add("style","font-weight:bold");
and ListBox1.Attributes.Add("style","font-weight:normal");
or even better is
// css
.active {font-weight:bold}
.notactive {font-weight:normal}
//c#
ListBox1.CssClass = "active";
ListBox1.CssClass = "notactive ";
you could try lb.Style.Remove("font-weight");
set the font bold in the click event of the link button and set the enable view state property to false in the click event itself which will reset the link to the normal foam in the other click