Implementing a dynamic ASP.NET 2.0 navigation interface (and keeping clean HTML & CSS separation) can be tricky. I came across this when working on a site that I've been putting off for the last few months. Lately I've been playing around with bit-masking a lot, so I thought I'd put it to good use in this scenario and try a different way of setting up navigation. Check it out!
For all those who are unfamiliar with how bit-masking works, here's a short tutorial. For those who know this concept already, you may skip forward down to the next code section.
1: public enum HeaderTabs {
2: None = 0, //empty mask = 00000
3: SignUp = 1, //2^0 = 00001
4: LogIn = 2, //2^1 = 00010
5: About = 4, //2^2 = 00100
6: FAQ = 8 //2^3 = 01000
7: Privacy = 16 //2^4 = 10000
8: }
9:
10: private Nullable<HeaderTabs> _flags = HeaderTabs.None;
11:
12: /// <summary>
13: /// Flag getter and setter
14: /// </summary>
15: public Nullable<HeaderTabs> Flags {
16: get { return _flags; }
17: set { _flags = value; }
18: }
19:
20: public void BitMasking() {
21: //To activate a Flag use the OR | operator
22: this.Flags = this.Flags | HeaderTabs.SignUp;
23: this.Flags = this.Flags | HeaderTabs.Privacy;
24:
25: //To Check if a Flag is active use the AND & operator
26: bool result;
27: if ( (this.Flags.Value & HeaderTabs.Privacy) > 0) {
28: result = true;
29: }
30:
31: return;
32: }
Some explanation of the above:
- Lines 1 - 8: HeaderTabs defines all of the available flags that can be set. Add and subtract the amount of enums as needed (keeping in mind that the values need to be powers of 2).
- Lines 15 - 17: Getter and setter for Flags.
- Lines 20 - 29: Here's where the magic is! We use bitwise operators (no that's not a typo in the code!) to set and check whether or not a flag has been set. The two most common bitwise operators that will be used in bit-masking are the OR operator (|, used to set a flag) and the AND operator (&, used to check the status of a flag). There are others (XOR and NOT) that I didn't have any use for in this post, but feel free to post comments if you are curious how to use them.
So pretty cool stuff huh?! For those of you who haven't used bit-masking yet before, bet you didn't know you could set multiple values to an enum. For those of you who have, well just stay along for the ride, we're getting to the point.
How does this tie into Master Pages and Dynamic Navigation? Here is the rest of the code to show how I implemented it into our navigation setup for the site.
MasterPage.Master (HTML)
1: <div id="page-header-nav">
2: <ul class="tabbed-menu">
3: <li runat="server" id="mnuBtnSignUp"><a href="#">Sign Up</a></li>
4: <li runat="server" id="mnuBtnLogin"><a href="#">Log In</a></li>
5: <li runat="server" id="mnuBtnAbout"><a href="#">About</a></li>
6: <li runat="server" id="mnuBtnFAQ"><a href="#">FAQ</a></li>
7: <li runat="server" id="mnuBtnPrivacy"><a href="#">Privacy</a></li>
8: </ul>
9: </div>
As you can see, I've set every li element to be a server side HTML control so that it can be hidden and shown as needed.
MasterPage.Master.cs
1: protected void Page_Load(object sender, EventArgs e) {
2: DisplayTabs();
3: }
4:
5: /// <summary>
6: /// Searches through bitmask of Visible Tabs and sets visiblity to true
7: /// </summary>
8: private void DisplayTabs() {
9:
10: if (this.VisibleTabs.HasValue) {
11: bool result;
12:
13: //About
14: this.mnuBtnAbout.Visible = IsTabVisible(this.VisibleTabs, HeaderTabs.About);
15:
16: //FAQ
17: this.mnuBtnFAQ.Visible = IsTabVisible(this.VisibleTabs, HeaderTabs.FAQ);
18:
19: //Login
20: this.mnuBtnLogin.Visible = IsTabVisible(this.VisibleTabs, HeaderTabs.LogIn);
21:
22: //Privacy
23: this.mnuBtnPrivacy.Visible = IsTabVisible(this.VisibleTabs, HeaderTabs.Privacy);
24:
25: //SignUp
26: this.mnuBtnSignUp.Visible = IsTabVisible(this.VisibleTabs, HeaderTabs.SignUp);
27: }
28: }
29:
30: /// <summary>
31: /// Returns true/false if a specific tab is included in the bitmask
32: /// </summary>
33: /// <param name="bitmask"></param>
34: /// <param name="tab"></param>
35: /// <returns></returns>
36: private bool IsTabVisible(Nullable<HeaderTabs> bitmask, HeaderTabs tab) {
37: bool result = false;
38:
39: if ( (bitmask.Value & tab) > 0 )
40: result = true;
41:
42: return result;
43: }
44:
45: private Nullable<HeaderTabs> _visibleTabs = HeaderTabs.None;
46:
47: /// <summary>
48: /// List of Visible Tabs on the Page
49: /// </summary>
50: public Nullable<HeaderTabs> VisibleTabs {
51: get { return _visibleTabs; }
52: set { _visibleTabs = value; }
53: }
54:
55: /// <summary>
56: /// Available Tabs for Top Navigation
57: /// </summary>
58: public enum HeaderTabs {
59: None = 0,
60: SignUp = 1,
61: LogIn = 2,
62: About = 4,
63: FAQ = 8,
64: Privacy = 16
65: }
The code is pretty self-explanatory once we've learned the concept of bit-masking.
- Lines 1 - 3: During the Page_Load event call DisplayTabs.
- Lines 8 - 28: Mapping between our server-side controls defined in the HTML of the Master Page, we set the visibility of each li item to the result of the IsTabVisible method.
- Lines 36 - 43: This method saves us from having to rewrite the bit-masking code for every tab.
- Lines 50 - 53: Making the VisibleTabs property public allows our child content pages easy access to determine which flag is set.
ChildPage.aspx.cs
1: protected void Page_Load(object sender, EventArgs e) {
2: SetPageDefaults();
3: }
4:
5: private void SetPageDefaults() {
6:
7: MasterPage master = this.Master;
8:
9: //Visible Tabs
10: master.VisibleTabs = master.VisibleTabs | HeaderTabs.SignUp;
11: master.VisibleTabs = master.VisibleTabs | HeaderTabs.LogIn;
12: master.VisibleTabs = master.VisibleTabs | HeaderTabs.FAQ;
13:
14: return;
15: }
Hope this article can provide something for everyone! Let me know if you have any questions.
Links: Bitwise operators in C#

2 new thoughts:
Anyone created this in VB.NET?
This could be easily converted to VB.NET. If you are interested feel free to email me and I may be able to put something together for you.
Post a Comment