tags:

views:

90

answers:

5

Hi everybody.

I'm trying to make a tabbed menu for the asp.net website I'm working on. One of the pre-requisite is obviously to color the current tab differently, so the user can know on which tab is currently is.

To do this, I made this method in my code-behind:

Protected Function GetCssClass(ByVal ctrl As LinkButton) As String
        If ctrl.ID = currentLink Then
            Return "current"
        Else
            Return String.Empty
        End If
    End Function

and I call the method like this in my aspx page:

<asp:LinkButton ID="LinkButton1" runat="server" PostBackUrl="/Default.aspx" CssClass="<%#GetCssClass(LinkButton1) %>" >Home</asp:LinkButton>                    
<asp:LinkButton ID="LinkButton2" runat="server" PostBackUrl="/Directory/page1.aspx" CssClass="<%#GetCssClass(LinkButton2) %>" >Page1</asp:LinkButton>

But the method is never hit... As I understand, the method should be called each time the LinkButton is drawn...

Does someone have an idea why?

Thanks in advance !


Edit: Just as a precision, all this code is in the masterpage.


Edit2: Here are the changes I made according to Quagland's suggestion.

In the aspx masterpage:

<asp:HiddenField ID="currentLink" runat="server" />
<asp:LinkButton ID="LinkButton1" runat="server" PostBackUrl="/Default.aspx" OnClick="LinkButton_Click" OnPreRender="LinkButton_PreRender" >Home</asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server" PostBackUrl="/OtherDirectory/Page1.aspx" OnClick="LinkButton_Click" OnPreRender="LinkButton_PreRender" >Page1</asp:LinkButton>
<asp:LinkButton ID="LinkButton3" runat="server" PostBackUrl="/OtherDirectory/Page2.aspx" OnClick="LinkButton_Click" OnPreRender="LinkButton_PreRender" >Page2</asp:LinkButton>
<asp:LinkButton ID="LinkButton4" runat="server" PostBackUrl="/OtherDirectory/Page3.aspx" OnClick="LinkButton_Click" OnPreRender="LinkButton_PreRender" >Page3</asp:LinkButton>

And in the code behind:

 Protected Sub LinkButton_Click(ByVal sender As Object, ByVal e As EventArgs) Handles LinkButton1.Click, LinkButton2.Click, LinkButton3.Click, LinkButton4.Click, LinkButton5.Click, LinkButton6.Click, LinkButton7.Click, LinkButton8.Click
        Dim lnk As LinkButton = CType(sender, LinkButton)
        currentLink.Value = lnk.ID
    End Sub

    Protected Function GetCssClass(ByVal ctrl As LinkButton) As String
        If ctrl.ID = currentLink.Value Then
            Return "current"
        Else
            Return String.Empty
        End If
    End Function


    Protected Sub LinkButton_PreRender(ByVal sender As Object, ByVal e As EventArgs) Handles LinkButton1.PreRender, LinkButton2.PreRender, LinkButton3.PreRender, LinkButton4.PreRender, LinkButton5.PreRender, LinkButton6.PreRender, LinkButton7.PreRender, LinkButton8.PreRender
        Dim lnk As LinkButton = CType(sender, LinkButton)
        lnk.CssClass = GetCssClass(lnk)
    End Sub

The problem is now that the click event is not always fired. On first click, nothing happens, but on second click on a tab, the click event is correctly triggered. Any clue ?

Edit3: Could it be that the value stored in the hidden field is reset each time the masterpage is reloaded (I mean, each link points to a couple masterpage + content page) ?

+2  A: 

You need to use <%= ... %> (i.e. replace # with =).

The hash form is used with data binding, you want to just create output.

For .NET 4 prefer <%: ... %> (use a colon) to automatically do HTML encoding.

Richard
Hi Richard, thanks for the fast answer. I just tried, without any more success... The function is still not accessed by using the `<%= %>` notation.Btw, why does the compiler accept this syntax here ? I thought I can't use those tags inside an `<asp:xxx />` tag.
Shimrod
@Shimrod: if this was not accepted by the compiler, you would see the `<%...%>` in the source in the client. If it is not working then there is something deeper at fault. Can you update the question with a complete .aspx (and code behind) without further dependencies that shows the problem?
Richard
I don't understand, I'm unable to reproduce the behavior I had before... But I'm sure the compiler told me that the `<% %>` I used couldn't be placed in an argument of an `<asp:xxx />` tag... strange...
Shimrod
A: 

<%# ... %> will work if you're OK with doing LinkButton1.DataBind() in your code-behind at the appropriate time.

Chris Dwyer
Indeed Chris. But I don't find this method "sexy", I'd prefer trying another way if possible (considering that right now I only have 8 tabs, but it could contain more of them...). Moreover, doing this seems to prevent my code to access the code behind the click event (which I'm going to use too).
Shimrod
+1  A: 

Set the CssClass in the code-behind. This will state your intent more clearly than calling DataBind on your linkbuttons if you use databinding syntax. Since you're doing it for multiple controls maybe stick them in a method called ApplyCssClasses.

zincorp
Thanks for the advice, I'll try to separate my code more often. (I'm not used to web development...)
Shimrod
+1  A: 

I'm not sure why <%= %> isn't working but personally I don't like to mix code and markup, I like to keep them completely separate.

I would suggest setting the CSS class in code perhaps on the page load event.

lnkPopulate.CssClass = "current"

Fishcake
+1  A: 

I have quickly tested a solution that might work for you. I'm just not sure where your 'currentlink' variable comes from. I have implemented it as a hidden field here.

In Masterpage.aspx:

<asp:HiddenField ID="currentLink" runat="server" />
<asp:LinkButton ID="LinkButton1" runat="server">Home</asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server">Page1</asp:LinkButton>

In code behind: use your original GetCssClass function add this:

Protected Sub LinkButton_PreRender(ByVal sender As Object, ByVal e As System.EventArgs)
                                    Handles LinkButton1.PreRender, LinkButton2.PreRender
    Dim lnk As LinkButton = CType(sender, LinkButton)
    lnk.CssClass = GetCssClass(lnk)
End Sub

I have put it in PreRender because i was using the LinkButton click events to set the hidden field value (and Click happens after Load but before PreRender):

Protected Sub LinkButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
                                Handles LinkButton1.Click, LinkButton2.Click
    Dim lnk As LinkButton = CType(sender, LinkButton)
    currentLink.Value = lnk.ID

End Sub

also, if there are numerous Linkbuttons, you may want to declare like:

 <asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton_Click" OnPreRender="LinkButton_PreRender">Home</asp:LinkButton>

EDIT: Here is another solution that will work with cross page postbacks. Not much code but you'll need to put some on every page. Anyway:

Masterpage.aspx:

<asp:LinkButton ID="LinkButton1" runat="server" PostBackUrl="Default.aspx">Home</asp:LinkButton>
<asp:LinkButton ID="LinkButton2" runat="server" PostBackUrl="Page1.aspx">Page1</asp:LinkButton>
<asp:LinkButton ID="LinkButton3" runat="server" PostBackUrl="Page2.aspx">Page2</asp:LinkButton>
<asp:LinkButton ID="LinkButton4" runat="server" PostBackUrl="Page3.aspx">Page3</asp:LinkButton>   

Masterpage.aspx.vb:

Public Sub SetCssClass(ByVal ctrl As String)
    CType(FindControl(ctrl), LinkButton).CssClass = "current"
End Sub

All content pages: *.aspx: add this directive to create a strongly typed reference to the masterpage

<%@ MasterType VirtualPath="~/MasterPage.master" %>

*.aspx.vb:

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Master.SetCssClass("LinkButton1") '' << put the name of the relevant link button here
End Sub
quagland
Thanks quagland ! Your solution is nice, but I still experience problems... I noticed that the click event is not always fired... Do you have an idea why it happens ? Usually, the first click is not taken in account, but the second one does.I'll update my post to reflect the changes I made, so you can see if I did something wrong. Thanks again ;-)
Shimrod
The use of cross page postbacks complicates things a little... You'll notice that each time you click the link for a different page, the click event won't fire but it will if you click the link for the same page.This is because a cross page postback is actually a new request on the destination page (ie. NOT really a postback). You can access the details of the previous page using Page.PreviousPage. You can check whether a cross page postback has occurred using Page.IsCrossPagePostback.So that's the reason... not sure of a solution
quagland
Ok thanks for the explanation, that's what I feared... Am I misusing the `<asp:LinkButton />` component ? The cross-page postback is not something I'm needing, so, if there is another way to go to another page, and keeping the click event, it would be welcome ! Otherwise, maybe I should open a new question, asking "how do I make a tabbed menu that doesn't use multiview" :-)
Shimrod
have you considered using the asp ajax extensions?http://www.asp.net/ajax/ajaxcontroltoolkit/Samples/Tabs/Tabs.aspx
quagland
Well I had a look at it, and it doesn't seem to be an option for my project, as as far as I understand how it works, every tab must be declared in the same page, and that's not what is required here :-/What I'm beginning to think is that I'll make each content page call the masterpage and change the css of its tab. I don't find this being a nice solution... but if I don't find anything else, that's what I'll certainly do.
Shimrod
I have added another solution above which is basically what you have just said - change the masterpage css witha call from the content page
quagland
Hi quagland. That's basically what I finally did yesterday, except I worked the reverse way: My MasterPage is looking in its ContentPage if a given hidden field is present, and if it is, gets its value to know which tab must be different.Thanks for your help, I'll validate your answer for being the one who lead me to the solution !
Shimrod