I have a page with a dynamically created command button.
I need to dynamically wire up a click event so I can grab the CommandArgument of the clicked button.
Button b = new Button();
b.ID = "btnTrigger2";
b.CssClass = "hiddenBtn";
b.CommandName = "lbl3";
b.Click += new EventHandler(btnTrigger_Click);
The problem is the last line - I can't wire up an EventHandler this way - I need to use the standard EventArgs instead of CommandEventArgs.
Anyone have any suggestions on getting this to work? There's got to be a way...
EDIT
Figured I'd post the code that finally worked in case anyone else tries to do the same thing.
`string tabLoadedScript = string.Empty;
string postBackScript = string.Empty;
string script = " <script language='javascript' type='text/javascript'>" + System.Environment.NewLine;
script += "function clientActiveTabChanged(sender, args) {" + System.Environment.NewLine;
int i = 0;
foreach(TabPanel tp in tc1.Tabs)
{
Button b = new Button();
b.ID = "btn" + tp.ClientID;
b.CssClass = "hiddenBtn";
b.CommandName = tp.ID;
b.Command += btnTrigger_Click;
this.form1.Controls.Add(b);
AsyncPostBackTrigger trg = new AsyncPostBackTrigger();
trg.ControlID = "btn" + tp.ClientID;
tabLoadedScript += "var isTab" + tp.ClientID + "loaded=$get('" + tp.Controls[0].ClientID + "');" + System.Environment.NewLine;
postBackScript += "if(!isTab" + tp.ClientID + "loaded && sender.get_activeTabIndex() == " + i + ") {" + System.Environment.NewLine;
postBackScript += "__doPostBack('" + b.ClientID + "','');}" + System.Environment.NewLine;
i++;
}
script += tabLoadedScript;
script += postBackScript;
script += "}" + System.Environment.NewLine;
script += "</script>";
this.ClientScript.RegisterClientScriptBlock(this.GetType(), "cs", script, false);
protected void btnTrigger_Click(object sender, CommandEventArgs e)
{
System.Threading.Thread.Sleep(2500);
Panel ctrl = (Panel) FindControlRecursive(this, "pnl" + e.CommandName);
ctrl.Visible = true;
}
public static Control FindControlRecursive(Control Root, string Id)
{
if(Root.ID == Id)
return Root;
foreach(Control Ctl in Root.Controls)
{
Control FoundCtl = FindControlRecursive(Ctl, Id);
if(FoundCtl != null)
return FoundCtl;
}
return null;
}
`
You can still access the CommandArgument using the the first argument passed to the click handler.
Something like:
protected void btnTrigger_Click(object sender, EventArgs e)
{
Button btnTrigger = sender as Button;
String commandArgument = btnTrigger.CommandArgument;
.
.
.
.
//Other code....
}
You need to use the Command event instead of the Click event. Also, assuming you're using a recent version of Visual Studio and .Net, you can simply change the event registration from
b.Click += new EventHandler(btnTrigger_Click);
to
b.Command += btnTrigger_Click
The explicit typing of the delegate is redundant and will be inferred by the compiler. You can now change the signature of your event handler to:
protected void btnTrigger_Click(object sender, CommandEventArgs e)
And the code should work as desired.
Unfortunately, the default code snippets in Visual Studio still generate this old-style event listener code.
Related
I need to create an HTML button dynamically in my ASP.NET C# codebehind, I must insert this button in my literal control, I use following syntax:
literal.Text+=<button id=\"MyButton\" runat=\"server\" OnServerClick=\"MyButton_Click\">Click Me</Button>";
button is displayed, it causes postback but my server click function (MyButton_Click) is not called, what is going wrong here? I should certainly use a literal, can I use ASP.NET controls in my literal?
I want to call a function after this button causes postback, can I use another objects in my literal? I should certainly use literals
thanks for your answers, I have a lot of codes in my literal, something like this:
......
......
dynTable += "</td></tr>";
dynTable += "<tr><td></td></tr>";
dynTable += "<tr><td></td></tr>";
dynTable += "<tr><td></td></tr>";
dynTable += "<tr><td></td></tr>";
dynTable += "<tr><td align=\"left\">";
dynTable += "<button id=\"MyButton\" type=\"submit\" runat=\"server\" OnServerClick=\"MyButton_Click\">Foo</button>";
dynTable += "</tr></td> </table> ";
}
}
//=====================================
dynTable += " </td>";
dynTable += " </tr>";
dynTable += " </table>";
dynTable += " </td>";
dynTable += " </tr>";
dynTable += " </table>";
dynTable += " </td>";
dynTable += " </tr>";
}
dynTable += "</table>";
}
ReviewPlace.Text = dynTable;
ReviewPlace is my asp.net literal object
You can't add Server - Html/Web controls that way. You have to create an object of Control in Page_Init/Page_Load event and add it to PlaceHolder's Controls collection.
Add PlaceHolder1 control in markup (.aspx)
<form id="form1" runat="server">
<asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder>
</form>
and write Page_Init handler,
protected void Page_Init(object sender, EventArgs e)
{
System.Web.UI.HtmlControls.HtmlButton button = new System.Web.UI.HtmlControls.HtmlButton();
button.InnerText = "OK";
//Event handler - Lambda (anonymous method) expression
button.ServerClick += (sa, ea) =>
{
Response.Write("button is pressed");
};
//Named Event handler
button.ServerClick += new EventHandler(button_ServerClick);
PlaceHolder1.Controls.Add(button);
}
void button_ServerClick(object sender, EventArgs e)
{
Response.Write("Another handler");
}
EDIT: I suggest you to use jQuery/JavaScript - ajax to request server resources instead of handling server-events if you wish/want to generate markup by hand. Alternative solution to this issue is to use Server constrols - especially GridView/ListView and I'm sure these controls and binding mechanism will solve that issue.
Another possibility is use of Table Server control. Have a look at sample:
//For ease of use I'v subclass the `TableRow`
public class Row : TableRow
{
public Row(int col)
{
for(int i=0;i<col;i++)
Cells.Add(new TableCell());
}
public TableCell this[int index]
{
get { return Cells[index]; }
}
}
and Page_Init code to populate Table object.
protected void Page_Init(object sender, EventArgs e)
{
Table table = new Table();
Row row1 = new Row(3);
row1[0].ColumnSpan = 3;
row1[0].Text = "Search";
table.Rows.Add(row1);
Row row2 = new Row(3);
row2[0].Text = "Enter keyword";
row2[1].Controls.Add(new TextBox());
table.Rows.Add(row2);
Row row3 = new Row(3);
row3[0].ColumnSpan = 3;
Button button = new Button();
button.Text = "Search";
button.Click += (sa, ea) => Response.Write("Button is pressed");
row3[0].Controls.Add(button);
table.Rows.Add(row3);
PlaceHolder1.Controls.Add(table);
}
As AVD points out, this isn't a very good idea.
However, if you do decide to continue down this path, you will need to post back by calling the client script function __doPostBack() function with the correct __EVENTTARGET and __EVENTARGUMENT properties set.
This SO post shows a quick and dirty hack workaround here for doing this, by placing a hidden asp:button on the screen, and then changing your code to call the hidden button click.
I want to create dynamic text box when user click on Add more link button.
For this I am using this code. And I have to mention that I am using master page.
protected void lnkAddMore_Click(object sender, EventArgs e)
{
if (Request.Cookies["value"] != null)
{
i = Convert.ToInt32(Request.Cookies["value"].Value) + 1 ;
}
for (int k = 1; k <= i; k++)
{
LiteralControl literal = new LiteralControl();
literal.Text = "<br /><br />";
Label newLabel = new Label();
newLabel.Text = "Choice" + " " + k.ToString();
newLabel.ID = "lblChoice_" + k.ToString();
newLabel.Attributes.Add("runat", "Server");
this.panelLabel.Controls.Add(newLabel);
this.panelLabel.Controls.Add(literal);
LiteralControl literal1 = new LiteralControl();
literal1.Text = "<br /><br />";
TextBox nexText = new TextBox();
nexText.ID = "txtChoice_" + k.ToString();
nexText.Attributes.Add("TextMode", "MultiLine");
nexText.Attributes.Add("runat", "Server");
panelTextbox.Controls.Add(nexText);
this.panelTextbox.Controls.Add(literal1);
Response.Cookies["value"].Value = i.ToString();
Session["Panel"] = panelTextbox;
}
}
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack)
{
if (Session["Panel"] != null)
{
ContentPlaceHolder content=new ContentPlaceHolder();
content.Controls.Add(Session["Panel"] as Panel);
}
}
}
Now I am facing trouble how to retrieve the data of the these text boxes after the clicking on the submit button so that I can store the values of there text boxes to database.
What will be code written for the click event of btnSave
protected void btnSave_Click(object sender, EventArgs e)
{
if (Session["Panel"] != null)
{
ContentPlaceHolder content_new = new ContentPlaceHolder();
for (int i = 1; i <= count; i++)
{
strControlName = "txtChoice_" + i.ToString();
TextBox objTextBox = (TextBox)content_new.FindControl(strControlName);
strTextBoxValues[i] = objTextBox.Text;
string str3 = strTextBoxValues[2];
}
}
}
This code is showing error for objTextBox. The error is NullReferenceException.
How to write stored procedure for saving data of above code?
The main problem is handling the parameter declaration, how to declare dynamic parameter for passing values so that value is saved for dynamic textbox?
Thanks.
I have already answered it here.
Lost dynamically created text box values
You can try this.
private string GetValue(string ControlID)
{
string[] keys = Request.Form.AllKeys;
string value = string.Empty;
foreach (string key in keys)
{
if (key.IndexOf(ControlID) >= 0)
{
value = Request.Form[key].ToString();
break;
}
}
return value;
}
Then to get the value
string txtChoice1value = GetValue("txtChoice1");
First of all when you dynamically create a control it doesn't need to be set "runat = sever".
Problem is in this line `ContentPlaceHolder content_new = new ContentPlaceHolder();` you make a new ContentPlaceHolder, this mean it doesn't have any control to be found.
Check this page. How To Create TextBox Control Dynamically at Runtime
You need to find the reference of your already created ContentPlaceHolder like-
ContentPlaceHolder cnt =(ContentPlaceHolder)this.Master.FindControl("ContentPlaceHolder1");
and then add the dynamically created Control in that ContentPlaceHolder as-
cnt.Controls.Add(Session["Panel"] as Panel);
Why you creating a new ContentPlaceHolder each time even when you have mentioned that you are using masterPage, so there must exists a ContentPlaceHolder..
Controls wont persist on postback have a look at http://www.denisbauer.com/ASPNETControls/DynamicControlsPlaceholder.aspx
I create dynamic LinkButton and I add LinkButton's Click Trigger to UpdatePanel.
Now, When I first click to any one of link button trigger is runing good and show my select whitout POSTBACK. After That, I click other LinkButton All Page Loading and POSTBACK running so Trigger Does Not Work!
What is the problem ? Please Help!
protected void Page_Load(object sender, EventArgs e)
{
ShowAllCar();
}
public void ShowAllCar()
{
dsAraclarTableAdapters.tblAraclarTableAdapter _t=new dsAraclarTableAdapters.tblAraclarTableAdapter();
dsAraclar.tblAraclarDataTable _m =_t.GetData();
int i=0;
UpdatePanel1.Triggers.Clear();
pnlAraclar.Controls.Clear();
foreach (DataRow _row in _m.Rows)
{
LinkButton _linkbutton =new LinkButton();
i++;
_linkbutton.ID ="Option" + i.ToString();
_linkbutton.Text = "<img src='" + _row["Resim"].ToString() + "' border='0'/> <b>" + _row["Marka"].ToString() + " " + _row["Model"].ToString() + "</b><br/>" + _row["Ozellikler"].ToString() + " : " + _row["KisFiyat"].ToString() + ":" + _row["YazFiyat"].ToString();
_linkbutton.CssClass="ContextMenuItem";
_linkbutton.PostBackUrl = "";
_linkbutton.Click +=new EventHandler(OnCarSelect);
pnlAraclar.Controls.Add(_linkbutton);
AsyncPostBackTrigger _trigger = new AsyncPostBackTrigger();
_trigger.ControlID = _linkbutton.ID;
_trigger.EventName = "Click";
UpdatePanel1.Triggers.Add(_trigger);
}
}
protected void OnCarSelect(object sender, EventArgs e)
{
lblSelection.Text = "You selected <b>" + ((LinkButton)sender).Text + "</b>.";
}
You need to add the controls back to the control tree earlier in the page life cycle:
PreInit Use this event for
the following:
...
* Create or re-create dynamic controls.
...
ASP.NET Page Life Cycle Overview
I'm writing am ASP.NET/C# project, it's a simple blog page with commnents.
Problem I'm having when button click you see comments load original blogload plus blogs and comments, trying to get it to load blog/comment selected only.
If I try not to load blog in page_load or have it only do if not postback nothing is displayed. Any help would be appreciated.
PS I know there are many blog engines out there but have specific reason.
protected void Page_Init(object sender, EventArgs e)
{
//ParseControls(GlobalVar.pathxsltver);
// BindInfo();
}
private void ParseControls(string myxslt)
{
//load the data
FileStream fs = new FileStream(Server.MapPath ( GlobalVar.compathver), FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
DataSet dset = new DataSet();
dset.ReadXml(fs);
fs.Close();
XPathDocument xdoc = new XPathDocument(Server.MapPath(GlobalVar.pathver ));
XmlDocument mydoc = new XmlDocument();
XPathNavigator navigator = xdoc.CreateNavigator();
XPathExpression expression = navigator.Compile("BlogItems/Blog");
expression.AddSort("ID", XmlSortOrder.Descending, XmlCaseOrder.UpperFirst, string.Empty, XmlDataType.Text);
XPathNodeIterator iterator = navigator.Select(expression);
int TheCnt = 0;
int cnt = GlobalVar.BlogCntDisplay;
string st = "<BlogItems>";
foreach (XPathNavigator item in iterator)
{
TheCnt++;
string sid = item.SelectSingleNode("ID").Value;
st = st + "<Blog id=\"" + sid + "\">" + item.InnerXml;
st = st + "<ComCnt>" + MyFunc.CountComments (sid,dset) + "</ComCnt></Blog>";
if (TheCnt == cnt) { break; }
}
st = st + "</BlogItems>";
mydoc.LoadXml(st);
XslCompiledTransform transform = new XslCompiledTransform();
XsltSettings settings = new XsltSettings(true,true);
transform.Load(Server.MapPath(myxslt),settings,null);
StringWriter sw = new StringWriter();
transform.Transform(mydoc, null, sw);
string result = sw.ToString();
//remove namespace
result = result.Replace("xmlns:asp=\"remove\"", "");
//parse control
Control ctrl = Page.ParseControl(result);
//find control to add event handler
//Boolean test = phBlog.FindControl("btnComment2").i;
phBlog.Controls.Add(ctrl);
XmlNodeList nList = mydoc.SelectNodes("//BlogItems/Blog/ID");
foreach (XmlNode objNode in nList)
{
Button btnComment = (Button) phBlog.FindControl("btnComment"+objNode.InnerText );
btnComment.CommandArgument = objNode.InnerText ;
btnComment.BorderWidth = 0 ;
btnComment.Command += new CommandEventHandler(Button1_Click);
}
}
protected void Page_Load(object sender, EventArgs e)
{
//if (!Page.IsPostBack )
//{ParseControls(GlobalVar.pathxsltver);}
ParseControls(GlobalVar.pathxsltver);
}
protected void Button1_Click(object sender, CommandEventArgs e)
{
Label1.Text = "Comm hit : " + e.CommandArgument.ToString();
ParseControls(GlobalVar.blogcommentsver );
}
You're question is kind of vague, but if I understand you correctly, you're wondering why the entire page refreshes when you just want to handle the button click?
Whenever you do any kind of postback, and that includes handling any events, the entire page is re-rendered. More than that, you're working with a brand new instance of your page class. The old one is dead and gone. That's just the way the web normally works.
If you only want to reload a part of the page, you need to use ajax. In ASP.Net land, that means placing your comments section inside an UpdatePanel control that can be refreshed.
I am trying to get a dynamically loaded LinkButton to fire a postback event, which I then handle.
I have across Command, CommandName and CommandArgument - which looked real useful.. So I started messing with that, but currently cannot get to work as desired.
The links are rendered within a table that is created on the fly, here is the code to generate them:
// The links are stored in Session since I was told that the objects need to remain intact across requests.
LinkButton GetEditCardLink(string card)
{
if (!IsPostBack)
{
TW("Creating Link for Card '" + card + "' and Placing in Session.", true);
LinkButton link = CreateEditLink(card);
Business.Session.Set<LinkButton>("LinkedCards_EditLink_" + card, link);
}
return Business.Session.Get<LinkButton>("LinkedCards_EditLink_" + card);
}
// Here the link itself is created, note the ID and Command details are set.
LinkButton CreateEditLink(string forCard)
{
TW("Setting Up Link for Card: " + forCard, true);
LinkButton rtn = new LinkButton();
rtn.ID = "Edit_" + forCard;
rtn.Text = Resources.Header("EditDetails");
rtn.CommandName = "Edit";
rtn.CommandArgument = forCard;
rtn.Command += new CommandEventHandler(RedirectToEdit);
rtn.Attributes["style"] = "display: block; text-align:center;";
return rtn;
}
// ... And the delegate I want called on PostBack..
void RedirectToEdit(object sender, CommandEventArgs e)
{
TW("RedirectToEdit Called:\r\nName: " + e.CommandName + "\r\nArgument: " + e.CommandArgument);
}
Trace confirms that the LinkButtons are being loaded correctly, and are only being creating once, so in theory they should be fine, but when I click the link, a PostBack is performed, but the RedirectToEdit method is not called?
All help gratefully received! :)
NOTE
Oh, I thought I should mention TW is just a utility method for Trace.Write/Warn :)
When you create a control that needs event handling you have to do it early enough in the processing that the event handler gets hooked up. Override OnInit for the page where you are creating the table and move the table creation code there. As #ScarletGarden suggests, you also need to add the control whether it's a PostBack or not. I believe that doing it in Page_Load is too late for the event to be detected if you add the control there.
Reference
Here is my trial, and it worked :
protected void Page_Load(object sender, EventArgs e)
{
//if (!IsPostBack)
//{
placeHolderAtPage.Controls.Add(CreateEditLink("forCard1"));
//}
}
LinkButton CreateEditLink(string forCard)
{
LinkButton rtn = new LinkButton();
rtn.ID = "Edit_" + forCard;
rtn.Text = "EditDetails";
rtn.CommandName = "Edit";
rtn.CommandArgument = forCard;
rtn.Command += new CommandEventHandler(RedirectToEdit);
rtn.Attributes["style"] = "display: block; text-align:center;";
return rtn;
}
void RedirectToEdit(object sender, CommandEventArgs e)
{
Response.Write("RedirectToEdit Called:\r\nName: " + e.CommandName + "\r\nArgument: " + e.CommandArgument);
}
If you decomment the IsPostBack line, RedirectToEdit will be useless.
Only binding codes can be under IsPostBack control.