I have linkbuttons in the Templatepagerfield. Now If I put the datapager in the Layout Template, I can do this:
Dim lnkBtn As LinkButton = CType(e.Item.FindControl("lnkBtn"), LinkButton)
without an error, but if I check linkbutton.visible in the immediate window, it comes back as Nothing, and if I try to make the linkbutton invisible, I do get an error. If I have the datapager outside of the ListView and I do the same thing, linkbutton.visible
is True (which it is). But if I try to make the link button invisible, nothing happens. I don't get an error, but I also can't make the link button invisible.
Does this make sense? I want programmatically control what link buttons get displayed in the datapager's TemplatePagerField. Is there a way to do this?
The good news with ASP.NET is you can do almost anything , it may just take a little explanation [:D]. FindControl will always return a value, but if it can't find the control then it will return Nothing, so you'll throw an exception when you try to access
a property/method of the control.
The problem here has to do with the concept of NamingContainers. Certain controls implement an interface called INamingContainer. What that does is allow multiple controls with the same ID to exist on the page, but be accessible individually and generate
unique IDs on the client. This is how, for example, you can declare a control in a ListView ItemTemplate with an ID, and you can reference it by that ID within that item, but it has a unique ID on the client. It saves you from having to use different IDs
for each item, the IDs just need to be unique within the NamingContainer. It's also the reason you'll see IDs like ListView1_DataPager1_ctl01_LinkButton1 if you view the source of a webpage. This is the ClientID of a LinkButton within a DataPager TemplateFied
within a ListView's LayoutTemplate. Each NamingContiner appends it's ID to the string, so you can see the original ID was LinkButton1, within a bunch of controls that are NamingContainers: a TemplatePagerField (ctl01 - autogenerated since I didn't declare
an ID), a DataPager (DataPager1), and a ListView (ListView1).
The reason this is significant is that FindControl searches only the current NamingContainer, it does not recursively drill down through the control hierarchy. So, you can access the LinkButton in question, you just need to dig through the control hierarchy
yourself to get a reference to it. The example below shows how:
Protected Sub ListView1_DataBound(ByVal sender As Object, ByVal e As System.EventArgs)
' First, we'll search the ListView to get a refernce to the DataPager
Dim DataPager1 As DataPager = DirectCast(ListView1.FindControl("DataPager1"), DataPager)
' The Controls collection of the DataPager contains the Fields, so we'll then search
' the appropriate field to get a reference to the LinkButton, in this case Control(1).
' We can't just search the DataPager because the field itself is a NamingContainer.
Dim LinkButton1 As LinkButton = DirectCast(DataPager1.Controls(1).FindControl("LinkButton1"), LinkButton)
LinkButton1.ControlStyle.ForeColor = System.Drawing.Color.Red
End Sub
Hope that helps.
Aaron
Don't forget to click "Mark as Answer" on the post that helped you. This credits that member, earns you a point and marks your thread as Resolved so everyone will know you have been helped.
What a wonderful, easy to understand explanation Aaron, thank you. I'm still having a problem with the syntax though. Linkbutton still comes back as nothing. Could this be because there's a TemplatePagerField between the Datapager and the linkbutton?
I'm glad it helped Diane. It's one of the concepts that's not always well explained, but is really critical when working with data controls.
I would double check which item in the Controls collection you're searching. In my example I had two fields, a NextPreviousPagerField then the TemplatePagerField, so I was searching Controls(1). You may need to update that based on your specific configuration.
One thing I'll do if I'm not sure for some reason is set a breakpoint in the code after I get a reference to the DataPager, go into debugging mode, and add a watch for the elements of the controls collection to confirm what they are.
Aaron
Don't forget to click "Mark as Answer" on the post that helped you. This credits that member, earns you a point and marks your thread as Resolved so everyone will know you have been helped.
I found it! DataPager1.Controls(2).Controls(1) contains the name and the text for the first link button I'm looking for. So I tried the:
Dim DataPager1 As DataPager = DirectCast(ListView1.FindControl("DataPager1"), DataPager)
Dim LinkButton1 As LinkButton = DirectCast(DataPager1.Controls(2).Controls(1).FindControl("LinkButton1"), LinkButton)
LinkButton1.Visible = False
I got no error, but setting LinkButton1.visible=false doesn't make the link button invisible.
I understand the concept, but I'm still not getting it to work,
I'd double check the name you're looking for in FindControl (I say that mostly because what's in your last post is different than the first).
To add to the confusion a little, FindControl can be used to find a control by the ID name, which is frequently easier, but you could actually get a reference to the control as well through the Controls collection. In my original example, the following
two statements both get the same result:
Dim LinkButton1 As LinkButton = DirectCast(DataPager1.Controls(1).FindControl("LinkButton1"), LinkButton)
Dim LinkButton1 As LinkButton = DirectCast(DataPager1.Controls(1).Control(0), LinkButton)
The complication you can run into using the Controls collection is that spaces in your markup can result in controls being in a place you wouldn't expect (e.g. if there's space between the PagerTemplate and LinkButton controls, Control(0) would be a Literal
control with the whitespace, and Control(1) would be the LinButton).
If my rambling hasn't helped, I may be able to help more if you post your markup.
Aaron
Don't forget to click "Mark as Answer" on the post that helped you. This credits that member, earns you a point and marks your thread as Resolved so everyone will know you have been helped.
Wow. this does get confusing. Is this documented anywhere that's fairly easy to understand? Sorry about the different names. I kept trying to keep things simpler than they are.
I have link buttons for the next and previous ten, next and previous hundred, and next and previous thousand. I only want to show those that make sense. I don't want to display any of the previous buttons for example if the user is on page 1.
Sorry, I didn't mean to make it too complicated. This worked for me:
Protected Sub ListView1_DataBound(ByVal sender As Object, ByVal e As System.EventArgs)
Dim DataPager1 As DataPager = DirectCast(ListView1.FindControl("DataPager1"), DataPager)
If (DataPager1.StartRowIndex = 0) Then
Dim PrevThousand As LinkButton = DirectCast(DataPager1.Controls(2).FindControl("PrevThousand"), LinkButton)
PrevThousand.Enabled = False
Dim PrevHundred As LinkButton = DirectCast(DataPager1.Controls(2).FindControl("PrevHundred"), LinkButton)
PrevHundred.Enabled = False
Dim PrevTen As LinkButton = DirectCast(DataPager1.Controls(2).FindControl("PrevTen"), LinkButton)
PrevTen.Enabled = False
End If
End Sub
Aaron
Don't forget to click "Mark as Answer" on the post that helped you. This credits that member, earns you a point and marks your thread as Resolved so everyone will know you have been helped.
Sigh. I have the prev buttons working, but not the next buttons. With what you gave me, I should be able to work it out. That's the best way to really understand it. Thank you for all your help. Without it I wouldn't have had a chance to figure it out.
I wish there was some place were all this was clearly explained. I have so many ListView questions!
Mainship
Participant
863 Points
2017 Posts
Do I have programmatic contol over the Datapager Template?
Mar 30, 2009 06:32 PM|LINK
I have a listview control with a datapager that has a templatepagerfield.
I have linkbuttons in the Templatepagerfield. Now If I put the datapager in the Layout Template, I can do this:
without an error, but if I check linkbutton.visible in the immediate window, it comes back as Nothing, and if I try to make the linkbutton invisible, I do get an error. If I have the datapager outside of the ListView and I do the same thing, linkbutton.visible is True (which it is). But if I try to make the link button invisible, nothing happens. I don't get an error, but I also can't make the link button invisible.
Does this make sense? I want programmatically control what link buttons get displayed in the datapager's TemplatePagerField. Is there a way to do this?
Diane
agolden
Star
7893 Points
1060 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 30, 2009 07:45 PM|LINK
Hi Diane,
The good news with ASP.NET is you can do almost anything , it may just take a little explanation [:D]. FindControl will always return a value, but if it can't find the control then it will return Nothing, so you'll throw an exception when you try to access a property/method of the control.
The problem here has to do with the concept of NamingContainers. Certain controls implement an interface called INamingContainer. What that does is allow multiple controls with the same ID to exist on the page, but be accessible individually and generate unique IDs on the client. This is how, for example, you can declare a control in a ListView ItemTemplate with an ID, and you can reference it by that ID within that item, but it has a unique ID on the client. It saves you from having to use different IDs for each item, the IDs just need to be unique within the NamingContainer. It's also the reason you'll see IDs like ListView1_DataPager1_ctl01_LinkButton1 if you view the source of a webpage. This is the ClientID of a LinkButton within a DataPager TemplateFied within a ListView's LayoutTemplate. Each NamingContiner appends it's ID to the string, so you can see the original ID was LinkButton1, within a bunch of controls that are NamingContainers: a TemplatePagerField (ctl01 - autogenerated since I didn't declare an ID), a DataPager (DataPager1), and a ListView (ListView1).
The reason this is significant is that FindControl searches only the current NamingContainer, it does not recursively drill down through the control hierarchy. So, you can access the LinkButton in question, you just need to dig through the control hierarchy yourself to get a reference to it. The example below shows how:
Protected Sub ListView1_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) ' First, we'll search the ListView to get a refernce to the DataPager Dim DataPager1 As DataPager = DirectCast(ListView1.FindControl("DataPager1"), DataPager) ' The Controls collection of the DataPager contains the Fields, so we'll then search ' the appropriate field to get a reference to the LinkButton, in this case Control(1). ' We can't just search the DataPager because the field itself is a NamingContainer. Dim LinkButton1 As LinkButton = DirectCast(DataPager1.Controls(1).FindControl("LinkButton1"), LinkButton) LinkButton1.ControlStyle.ForeColor = System.Drawing.Color.Red End SubHope that helps.
Aaron
Mainship
Participant
863 Points
2017 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 30, 2009 08:48 PM|LINK
What a wonderful, easy to understand explanation Aaron, thank you. I'm still having a problem with the syntax though. Linkbutton still comes back as nothing. Could this be because there's a TemplatePagerField between the Datapager and the linkbutton?
Diane
agolden
Star
7893 Points
1060 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 30, 2009 09:05 PM|LINK
I'm glad it helped Diane. It's one of the concepts that's not always well explained, but is really critical when working with data controls.
I would double check which item in the Controls collection you're searching. In my example I had two fields, a NextPreviousPagerField then the TemplatePagerField, so I was searching Controls(1). You may need to update that based on your specific configuration.
One thing I'll do if I'm not sure for some reason is set a breakpoint in the code after I get a reference to the DataPager, go into debugging mode, and add a watch for the elements of the controls collection to confirm what they are.
Aaron
Mainship
Participant
863 Points
2017 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 30, 2009 10:08 PM|LINK
I found it! DataPager1.Controls(2).Controls(1) contains the name and the text for the first link button I'm looking for. So I tried the:
Dim DataPager1 As DataPager = DirectCast(ListView1.FindControl("DataPager1"), DataPager)
Dim LinkButton1 As LinkButton = DirectCast(DataPager1.Controls(2).Controls(1).FindControl("LinkButton1"), LinkButton)
LinkButton1.Visible = False
I got no error, but setting LinkButton1.visible=false doesn't make the link button invisible.
I understand the concept, but I'm still not getting it to work,
Diane
agolden
Star
7893 Points
1060 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 30, 2009 11:20 PM|LINK
I'd double check the name you're looking for in FindControl (I say that mostly because what's in your last post is different than the first).
To add to the confusion a little, FindControl can be used to find a control by the ID name, which is frequently easier, but you could actually get a reference to the control as well through the Controls collection. In my original example, the following two statements both get the same result:
Dim LinkButton1 As LinkButton = DirectCast(DataPager1.Controls(1).FindControl("LinkButton1"), LinkButton)The complication you can run into using the Controls collection is that spaces in your markup can result in controls being in a place you wouldn't expect (e.g. if there's space between the PagerTemplate and LinkButton controls, Control(0) would be a Literal control with the whitespace, and Control(1) would be the LinButton).
If my rambling hasn't helped, I may be able to help more if you post your markup.
Aaron
Mainship
Participant
863 Points
2017 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 31, 2009 01:05 AM|LINK
Wow. this does get confusing. Is this documented anywhere that's fairly easy to understand? Sorry about the different names. I kept trying to keep things simpler than they are.
Here's my markup:
<asp:DataPager ID="DataPager1" runat="server" PageSize="50" PagedControlID="ListView1">
<Fields>
<asp:TemplatePagerField>
<PagerTemplate>
<asp:Label runat="server" ID="TotalItemsLabel"
Text="<%# Container.TotalRowCount%>" />
Results | Viewing Results
<%# Container.StartRowIndex + 1 %> -
<%# Container.StartRowIndex+Container.PageSize %>
| Viewing Page
<%#(Container.StartRowIndex / Container.PageSize) + 1 %>
of
<%#CInt(Container.TotalRowCount / Container.PageSize)%>
<br />
</PagerTemplate>
</asp:TemplatePagerField>
<asp:NextPreviousPagerField ButtonType="Link" ShowFirstPageButton="True"
ShowNextPageButton="False" ShowPreviousPageButton="False" FirstPageText="First Page" />
<asp:TemplatePagerField OnPagerCommand="PagerCommand">
<PagerTemplate>
<asp:LinkButton ID="PrevThousand" runat="server" CommandName="PrvTh" ToolTip="Previous Thousand Pages"><<<</asp:LinkButton>
<asp:LinkButton ID="PrevHundred" runat="server" CommandName="PrvHn" ToolTip="Previous Hundred Pages"><<</asp:LinkButton>
<asp:LinkButton ID="PrevTen" runat="server" CommandName="PrvTn" ToolTip="Previous Ten Pages"><<</asp:LinkButton>
</PagerTemplate>
</asp:TemplatePagerField>
<asp:NumericPagerField ButtonCount="10" />
<asp:TemplatePagerField OnPagerCommand="PagerCommand">
<PagerTemplate>
<asp:LinkButton ID="NextTen" runat="server" CommandName="NxtTn" ToolTip="Next Ten Pages">>></asp:LinkButton>
<asp:LinkButton ID="NextHundred" runat="server" CommandName="NxtHn" ToolTip="Next Hundred Pages">>></asp:LinkButton>
<asp:LinkButton ID="NextThousand" runat="server" CommandName="NxtTh" ToolTip="Next Thousand Pages">>>></asp:LinkButton>
</PagerTemplate>
</asp:TemplatePagerField>
<asp:NextPreviousPagerField ButtonType="Link" ShowLastPageButton="True"
ShowNextPageButton="False" ShowPreviousPageButton="False" LastPageText="Last Page" />
</Fields>
</asp:DataPager>
I have link buttons for the next and previous ten, next and previous hundred, and next and previous thousand. I only want to show those that make sense. I don't want to display any of the previous buttons for example if the user is on page 1.
Diane
agolden
Star
7893 Points
1060 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 31, 2009 01:50 AM|LINK
Hi Diane,
Sorry, I didn't mean to make it too complicated. This worked for me:
Protected Sub ListView1_DataBound(ByVal sender As Object, ByVal e As System.EventArgs) Dim DataPager1 As DataPager = DirectCast(ListView1.FindControl("DataPager1"), DataPager) If (DataPager1.StartRowIndex = 0) Then Dim PrevThousand As LinkButton = DirectCast(DataPager1.Controls(2).FindControl("PrevThousand"), LinkButton) PrevThousand.Enabled = False Dim PrevHundred As LinkButton = DirectCast(DataPager1.Controls(2).FindControl("PrevHundred"), LinkButton) PrevHundred.Enabled = False Dim PrevTen As LinkButton = DirectCast(DataPager1.Controls(2).FindControl("PrevTen"), LinkButton) PrevTen.Enabled = False End If End SubAaron
Mainship
Participant
863 Points
2017 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 31, 2009 02:45 AM|LINK
Sigh. I have the prev buttons working, but not the next buttons. With what you gave me, I should be able to work it out. That's the best way to really understand it. Thank you for all your help. Without it I wouldn't have had a chance to figure it out.
I wish there was some place were all this was clearly explained. I have so many ListView questions!
Diane
Mainship
Participant
863 Points
2017 Posts
Re: Do I have programmatic contol over the Datapager Template?
Mar 31, 2009 03:03 AM|LINK
Yeah!
Dim NextThousand As LinkButton = DirectCast(DataPager1.Controls(4).FindControl("NextThousand"), LinkButton)
NextThousand.Visible = False
Dim NextHundred As LinkButton = DirectCast(DataPager1.Controls(4).FindControl("NextHundred"), LinkButton)
NextHundred.Visible = False
Dim NextTen As LinkButton = DirectCast(DataPager1.Controls(4).FindControl("NextTen"), LinkButton)
NextTen.Visible = False
Figured it out, it's working, again, because of your help. Thank you!
Diane