i created a textbox, a button and a panel in a page. So my aim is to create links which will be put inside a panel. However, it turns out that every time i add another one, it seems to replace the previously created link. Is there a way to just add the links, not replacing previously created links? I really don't have a background that much in ASP.
This is the code I researched.
Protected Sub Button1_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Button1.Click
Dim link As New HyperLink()
Dim ltr As New Literal()
link.Text = TextBox1.Text
link.NavigateUrl = "Default.aspx?field1=" + TextBox2.Text + " "
ltr.Text = "<br/>"
Panel1.Controls.Add(ltr)
Panel1.Controls.Add(link)
Please help me. Thanks!
As said by #Rex, when post back occurs dynamically controls will be removed from the page until we retain them in Init Event.
While adding controls to PlaceHolder, save the same data like ID, Text..etc. in a object like session variable and retrieve the same data in Page Init event and add to the place holder.
protected void Page_Init(object sender, EventArgs e)
{
// Retrieve from session variable and add the same data to the place holder.
}
I am sure everyone who programmed with user controls for asp.net came across situations where you needed a certain way to check whether a user control has been loaded for the first time or it has been re-loaded. Has anyone come up with any other solutions other than setting hidden "currentOpenControl" flag(s). If you are wondering as to do I need to check whether control is open for first time or re-open again, then one of the big reasons is databinding. When the control is open for first time, that is when I want to databind, afterwards on re-open, if I databind again I will lose any changes user might have added.
So I am just wondering if anyone has a more elegant solution than setting flags whether control is open or not.
Thanks
The only way I've ever managed to do this is by using the ViewState...
Private Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
If ViewState["postBack"] Is Nothing Then
' Do everything you'd normally do with Page.IsPostBack
ViewState["postBack"] = true
End
End Sub
Or for C#...
protected void Page_Load(object sender, EventArgs e)
{
if (ViewState["postBack"] == null)
{
// Do everything you'd normally do with Page.IsPostBack
ViewState["postBack"] = true;
}
}
You can get using this, its in VB.NET convert to c#
Private currentPage As Page = HttpContext.Current.Handler
If (Not currentPage.IsPostBack) Then
End if
I am building a wizard in asp.net. I have an main aspx page which will have NEXT and PREVIOUS button for Navigation. On click of each NEXT or PREVIOUS appropriate user control will be loaded.
In one user control I have to create dynamic checkboxes as shown below:
Public Class ucQuestion
Inherits System.Web.UI.UserControl
#Region "UserControl Events"
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Try
If Not (Page.IsPostBack) Then
AddControls(0)
End If
Catch ex As Exception
Throw ex
End Try
End Sub
#End Region
Protected Friend Sub AddControls(ByVal iListQuestionCount As Integer)
Try
Dim oExam As New BusinessObject.Wizard.ExamVM
If (System.Web.HttpContext.Current.Session(BusinessLayer.Constants.WizardObjectCollection) IsNot Nothing) Then
oExam = DirectCast(System.Web.HttpContext.Current.Session(BusinessLayer.Constants.WizardObjectCollection), BusinessObject.ExamWizard.ExamVM)
End If
'divQuestion.Controls.Clear()
Dim ctrl As New Literal
ctrl.ID = "lit" + iListQuestionCount.ToString()
ctrl.Text = oExam.Wizard.ExamQuestions(iListQuestionCount).Label
divQuestion.Controls.Add(ctrl)
For iLoopChildCount As Integer = 0 To oExam.Wizard.ExamQuestions(iListQuestionCount).Choices.Count - 1
Dim childctrl As New CheckBox
'childctrl.AutoPostBack = True
childctrl.ID = "chk" + (iLoopChildCount + 1).ToString()
childctrl.Text = oExam.Wizard.ExamQuestions(iListQuestionCount).Choices(iLoopChildCount).Label
childctrl.Checked = oExam.Wizard.ExamQuestions(iListQuestionCount).Choices(iLoopChildCount).IsSelected
'AddHandler childctrl.CheckedChanged, AddressOf OnCheckedClick
divQuestion.Controls.Add(childctrl)
Next
Catch ex As Exception
Throw ex
End Try
End Sub
NoW the problem is in my Main.aspx page if user has selected any checkbox in usercontrol I want to save the value in session on NEXT button Navigation click event.
I tried following code in NEXT Button Click but it was unsucessfull.
For iLoopChildCount As Integer = 0 To oExamQuestions(ListIndex).Choices.Count - 1
Dim ctrl As Control
If (ucQuestion1.FindControl("chk" + (iLoopChildCount + 1).ToString()) IsNot Nothing) Then
ctrl = DirectCast(ucQuestion1.FindControl("chk" + (iLoopChildCount + 1).ToString()), CheckBox)
If (DirectCast(ctrl, CheckBox).Checked) Then
oBallotQuestions(ListIndex).Choices(iLoopChildCount).IsSelected = True
End If
End If
Next
That's the hard way.
Here is the easy way.
Define an interface and implement it in the User Control that represents this action. This might be GetNamesOfSelectedValues or whatever is appropriate. (Technically an interface isn't required, but I find it good practice and it makes for "more well defined contracts" in many cases.)
Use the interface defined on said Child in the Parent page code. Use this only after the OnLoad of the Child Control (which happens after the page load event) or the controls will not be restored yet.
That is, the parent should not know about any controls in the custom User Control.
This approach works well.
I'm having a problem with a Web Control that is dynamically created and inserted in my page. I create a couple of LinkButtons, depending on the data of the search that was made, and I'm trying to add an Event Handler to each of the Buttons, so it would filter the result.
The controls are initialized properly, but the event is never fired.
Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init
Controls.Clear()
Dim btn As Controls.LocalizableLinkButton
For Each element As Generic.KeyValuePair(Of String, ResultFilterData) In m_list
btn = New LocalizableLinkButton
btn.ID = m_Name & "$lnk" & count
btn.Label = element.Value.Label.Append(" (" + CStr(element.Value.Count) + ")")
btn.CommandArgument = element.Value.Key
AddHandler btn.Click, AddressOf Me.btn_Click
Controls.Add(btn)
Next
End Sub
Since this code is in Page_Init all the controls should be recreated on a postback. (The LocalizableLinkButton is just an extension of a LinkButton to add multilingual features to the text).
The problem is that the method btn_Click is never called. The Link Buttons are properly initialized on the callback, with the same ID's as before. But the event doesn't fire.
I'm using ASP.Net 2.0
Any ideas?
I finally figured out the problem ASP.NET had with my Link Buttons.
The error was in using a '$' sign in my ID for each LinkButton. ASP.NET apparently uses the $ sign to build the control hierarchy when it creates the Postback Javascript. Therefore it thinks that the LinkButtons are nested within a control that does not exist. And so the events aren't fired of course.
Once I removed the $ signs it worked properly.
You probably want to put this piece of code in the Page_Load and see. It's generally advised not to access controls in this Page_Init as there is no guarantee of the controls been created at this stage.
I'm no VB guy but i put this into the codebehind of the default.aspx and it works fine.
protected void Page_Load(object sender, EventArgs e)
{
Button button = new Button();
button.Click += new EventHandler(button_Click);
button.Text = "test";
Form.Controls.Add(button);
}
void button_Click(object sender, EventArgs e)
{
throw new NotImplementedException();
}
Classic scenario: Take user input, get a search-result and display it in pages to the user. I then need to display buttons for First, Next, Previous etc, and I maintain the users current page in viewstate. All is good, works fine.
Then I need to implement clickable page numbers, ie. 1-2-3-4-5-6 etc.
Rendering them is simple. I generate a linkbutton control at runtime, add commandargument with the page number and add a handler to it, so click are to be handled. Then I add it to a placeholder, and it is displayed as expected.
But then... If I did not already have a shaved head, I would be pulling out my hair getting the events to fire as expected every time.
How should I do this, so my events are always wired up and able to fire when the paging-linkbuttons are called?
Below is the important parts of the code, some pseudo to make it (hopefully) easier to understand, what I am doing.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Search()
End If
End Sub
Sub Search
'Misc databinding stuff, searches and displays results for the page specified in Me.CurrentPage
RenderPagingControls()
End Sub
Sub RenderPagingControls
'loop throug pagenumbers, Build a linkbutton control, add it to a placeholder
AddHandler lbn.Click, AddressOf lbnNumber_Click
lblPageNumbers.Controls.Add(lbn)
...
End Sub
Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim b As LinkButton = CType(sender, LinkButton)
Me.CurrentPage = CInt(b.CommandArgument)
Search()
End Sub
Public Property CurrentPage() As Integer
Get
Dim o As Object = Me.ViewState("CurrentPage")
If o Is Nothing Then
Return 1
Else
Return CType(o, Integer)
End If
End Get
Set(ByVal value As Integer)
Me.ViewState("CurrentPage") = value
End Set
End Property
Protected Sub lbnNumber_Click(ByVal sender As Object, ByVal e As EventArgs)
Dim b As LinkButton = CType(sender, LinkButton)
Me.CurrentPage = CInt(b.CommandArgument)
Search()
End Sub
I'm going to recommend against a LinkButton and recommend Hyperlinks / QueryString parameters instead. For several reasons:
Your page will be much more efficient without the viewstate overhead of a link button.
If these are public facing pages, you'll get better indexing of all the pages if they can be accessed via hyperlinks (and indexed via search engines).
You'll find them much easier to implement. No event management, etc.
You would redefine your CurrentPage method as (hopefully this is correct, I'm better at C# than vb.net):
Public Property CurrentPage() As Integer
Get
Dim o As Object = Me.Request.QueryString("page")
If o Is Nothing Then
Return 1
Else
Return CType(o, Integer)
End If
End Get
End Property
Then just add hyperlinks for each page.
<a href='mypage.aspx?page=1'>1</a> - <a href='mypage.aspx?page=2'>2</a>
etc...
Alternative: If you want to use the LinkButton, you might want to consider putting a single LinkButton in a repeater. Then the only event you have to worry about is the OnItemCommand event. Then no dynamic controls or events. Something like this:
<asp:Repeater ID="rptPages" runat="server" OnItemCommand='doPaging'>
<ItemTemplate>
<asp:LinkButton ID="LinkButton1" runat="server" Text='<%# (Container.DataItem).ToString() %>'
CommandArgument='<%# (Container.DataItem).ToString() %>' />
</ItemTemplate>
<SeparatorTemplate>-</SeparatorTemplate>
</asp:Repeater>
Bind this control to an array (or list) of consecutive Integers (as many are there are pages). Then in your doPaging function (as I call it), check RepeaterCommandEventArgs.CommandArgument to get the page number.
Thanks for the answers, guys. I tried out Austins first, but I must be missing something, because I keep getting the same behavior of link buttons only working every second time... So I gave up on that, and saw the alternative solution with the repeater by Keltex! It is as brilliant as it is simple, and we don't have to worry about any page life-cycle bullshit.
It just really works! ;)
If somebody should need something similar in the future, here is the relevant code behind the scenes:
Sub Search()
...
RenderPagingControls()
End Sub
Sub RenderPagingControls()
Dim pages As New ArrayList
For i As Integer = 1 To Me.PageCount
pages.Add(i)
Next
repPageNumbersTop.DataSource = pages
repPageNumbersTop.DataBind()
repPageNumbersBottom.DataSource = pages
repPageNumbersBottom.DataBind()
End Sub
Public Property CurrentPage() As Integer
Get
Dim o As Object = Me.ViewState("CurrentPage")
If o Is Nothing Then
Return 1
Else
Return CType(o, Integer)
End If
End Get
Set(ByVal value As Integer)
Me.ViewState("CurrentPage") = value
End Set
End Property
Public Property PageCount() As Integer
Get
Dim o As Object = Me.ViewState("PageCount")
If o Is Nothing Then
Return 0
Else
Return CType(o, Integer)
End If
End Get
Set(ByVal value As Integer)
Me.ViewState("PageCount") = value
End Set
End Property
Protected Sub repPageNumbersTop_ItemCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.RepeaterCommandEventArgs) Handles repPageNumbersTop.ItemCommand, repPageNumbersBottom.ItemCommand
Me.CurrentPage = CType(e.CommandArgument, Integer)
Search()
End Sub
Private Sub repPageNumbersTop_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles repPageNumbersTop.ItemDataBound, repPageNumbersBottom.ItemDataBound
If e.Item.ItemType = ListItemType.Item Or e.Item.ItemType = ListItemType.AlternatingItem Then
Dim lbn As LinkButton = CType(e.Item.FindControl("lbnPageNumber"), LinkButton)
If lbn.CommandArgument = Me.CurrentPage.ToString Then
lbn.Enabled = False
End If
End If
End Sub
This code works (sorry it's in C#):
protected void SearchButton_Click(object sender, EventArgs e)
{
//clear the collection!
pnlPageNumber.Controls.Clear();
//simulate search
System.Random rnd = new Random();
//create page buttons
for (int i = 0; i < rnd.Next(3, 15); i++)
{
LinkButton lb = new LinkButton();
pnlPageNumber.Controls.Add(lb);
lb.ID = "btn" + i;
lb.Text = i.ToString();
lb.CommandArgument = i.ToString();
lb.Command += new CommandEventHandler(linkbutton_Command);
//optional literal
pnlPageNumber.Controls.Add(new LiteralControl(" "));
}
ViewState["control#"] = Panel1.Controls.Count;
}
protected void Page_Load(object sender, EventArgs e)
{
if (IsPostBack)
{
//Recreate link buttons
//This is necessary to ensure proper event binding
int count = 0;
if (ViewState["control#"] != null)
count = (int)ViewState["control#"];
for (int i = 0; i < count; i++)
{
LinkButton lb = new LinkButton();
pnlPageNumber.Controls.Add(lb);
lb.ID = "btn" + i; //make sure IDs are the same here and on Search
lb.Command += new CommandEventHandler(linkbutton_Command);
//this is not necessary, but if you do, make sure its in both places
pnlPageNumber.Controls.Add(new LiteralControl(" "));
}
}
}
void linkbutton_Command(object sender, CommandEventArgs e)
{
Response.Write(e.CommandArgument.ToString() + " CLICK<br />");
}
You could use the DataPager control -- the only limitation is you have to use it with the ListView control, but you should be able to represent your data using the ListView control fairly easily because it is very flexible. You can set the DataSource of the ListView control to the result of your data result, whether that be a DataSet, Collection, Array, etc.
To create the paging controls with "first", "last", and page numbers, set up the DataPager like this (where ListView1 is the ID of your ListView control):
<asp:DataPager ID="DataPager1" runat="server"
PagedControlID="ListView1" PageSize="25">
<Fields>
<asp:NextPreviousPagerField FirstPageText="first" ShowFirstPageButton="True"
ShowNextPageButton="False" ShowPreviousPageButton="False" />
<asp:NumericPagerField />
<asp:NextPreviousPagerField LastPageText="last" ShowLastPageButton="True"
ShowNextPageButton="False" ShowPreviousPageButton="False" />
</Fields>
</asp:DataPager>
By design, the DataPager uses the whole result set from the database, but you can improve the performance by caching the result and using that on the subsequent requests.
Hope this helps.
iirc... adding controls dynamically at runtime is a bit tricky. The control tree must be rebuilt during post back... but before viewstate is loaded (not sure when in the page life cycle... but way before page load). So... your problem is that by the time asp.net is trying to figure out your event the actual originating control has not yet been created.