ASP.NET Forms Disabled CSS for BootStrap

The following CSS is to handle Enabled set to true in any WebControl.

/* -- Bootstrap Additions - ASP.NET Disabled ----------------- */

input[type="radio"].aspNetDisabled,
input[type="checkbox"].aspNetDisabled,
.radio-inline.aspNetDisabled,
.checkbox-inline.aspNetDisabled,
.radio.aspNetDisabled label,
.checkbox.aspNetDisabled label
{
    cursor: not-allowed;
}

.btn.aspNetDisabled
{
    pointer-events: none;
    cursor: not-allowed;
    filter: alpha(opacity=65);
    -webkit-box-shadow: none;
    box-shadow: none;
    opacity: .65;
}

.btn-default.aspNetDisabled,
.btn-default.aspNetDisabled:hover,
.btn-default.aspNetDisabled:focus,
.btn-default.aspNetDisabled:active,
.btn-default.aspNetDisabled.active
{
    background-color: #fff;
    border-color: #ccc;
}

.btn-primary.aspNetDisabled,
.btn-primary.aspNetDisabled:hover,
.btn-primary.aspNetDisabled:focus,
.btn-primary.aspNetDisabled:active,
.btn-primary.aspNetDisabled.active
{
    background-color: #428bca;
    border-color: #357ebd;
}

.btn-success.aspNetDisabled,
.btn-success.aspNetDisabled:hover,
.btn-success.aspNetDisabled:focus,
.btn-success.aspNetDisabled:active,
.btn-success.aspNetDisabled.active
{
    background-color: #5cb85c;
    border-color: #4cae4c;
}

.btn-info.aspNetDisabled,
.btn-info.aspNetDisabled:hover,
.btn-info.aspNetDisabled:focus,
.btn-info.aspNetDisabled:active,
.btn-info.aspNetDisabled.active
{
    background-color: #5bc0de;
    border-color: #46b8da;
}

.btn-warning.aspNetDisabled,
.btn-warning.aspNetDisabled:hover,
.btn-warning.aspNetDisabled:focus,
.btn-warning.aspNetDisabled:active,
.btn-warning.aspNetDisabled.active
{
    background-color: #f0ad4e;
    border-color: #eea236;
}

.btn-danger.aspNetDisabled,
.btn-danger.aspNetDisabled:hover,
.btn-danger.aspNetDisabled:focus,
.btn-danger.aspNetDisabled:active,
.btn-danger.aspNetDisabled.active
{
    background-color: #d9534f;
    border-color: #d43f3a;
}

.dropdown-menu > .aspNetDisabled > a,
.dropdown-menu > .aspNetDisabled > a:hover,
.dropdown-menu > .aspNetDisabled > a:focus,
.dropdown-menu > li > a.aspNetDisabled,
.dropdown-menu > li > a.aspNetDisabled:hover,
.dropdown-menu > li > a.aspNetDisabled:focus
{
    color: #777;
}

.dropdown-menu > .aspNetDisabled > a:hover,
.dropdown-menu > .aspNetDisabled > a:focus,
.dropdown-menu > li > a.aspNetDisabled:hover,
.dropdown-menu > li > a.aspNetDisabled:focus
{
    text-decoration: none;
    cursor: not-allowed;
    background-color: transparent;
    background-image: none;
    filter: progid:DXImageTransform.Microsoft.gradient(enabled = false);
}

 

ASP.NET Membership Log Out

My boss likes to say “never use the words ‘simple’ or ‘easy’ in our line of work” and today was one of those days that demonstrates exactly why he loves this saying.

We were asked to setup an auto logout feature that redirects to the login screen. I’ve done so much Windows Authentication work that I’ve never actually had to build this functionality. I went straight to my favorite search engine and I found the following code.

FormsAuthentication.SignOut();
Session.Abandon();
FormsAuthentication.RedirectToLoginPage();

Everyone was commenting about how this worked great and lo and behold it wasn’t working. More research and I found an article that explained that the above neglected to clear cookies sometimes and that to 100% ensure a sign out you should clear the forms authentication and session cookies.

The following code is what I ended up using in our application. It only expires the cookies that are forms authentication and session related.

FormsAuthentication.SignOut();
Session.Abandon();

var cookies = new List<string>
{
    "ASP.NET_SessionId", 
    FormsAuthentication.FormsCookieName, 
    ".ASPXROLES"
};

foreach (var cookie in cookies)
{
    if (Request.Cookies.AllKeys.Contains(cookie))
    {
        Request.Cookies[cookie].Expires = DateTime.Now.AddYears(-1);
    }
}

FormsAuthentication.RedirectToLoginPage();

SQL Saturday Baton Rouge 2014

First, SQL Saturday Baton Rouge 2014 has opened registration and placed the session list online. If you’re interested in development at all this is a must attend event. The sessions span all areas of development. The tracks include: .NET, Business Intelligence, Career Development, CIO/IT Manager, DBA, IT Pro, PowerShell, SharePoint, SQL Dev, and Web/Mobile dev. Please visit the website and sign up if you’re interested.

Secondly, I will be presenting “Testable WebForms with MVP”. This will be an intermediate topic and I’ll be assuming experience using ASP.NET WebForms and a basic understanding of unit testing. All code examples will be in C#. Here’s the description I sent in:

MVC is all the rage but what about all the code you already have written in ASP.NET WebForms? How can you make it maintainable and testable? In this session, I’ll show how you can make WebForms applications testable using Model-View-Presenter.

ASP.NET Forms Bootstrap Menu Control

When I couldn’t find an ASP.NET Form menu control that was compatible with Bootstrap 3.1, I did what every other developer would do: I created one. Enjoy!

Here’s the HTML markup view:

<div class="navbar navbar-inverse navbar-static-top" role="navigation">
    <div class="container" style="padding: 0; margin: 0;">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
        </div>
        <div class="navbar-collapse collapse">
            <jk:BootstrapMenu ID="BootstrapMenu1" runat="server">
                <Items>
                    <asp:MenuItem Text="Home" NavigateUrl="#" />
                    <asp:MenuItem Text="About" NavigateUrl="#" />
                    <asp:MenuItem Text="Contact" NavigateUrl="#" />
                    <asp:MenuItem Text="Drop Down">
                        <asp:MenuItem Text="Action" NavigateUrl="#" />
                        <asp:MenuItem Text="Another action" NavigateUrl="#" />
                        <asp:MenuItem Text="Something else here" NavigateUrl="#" />
                    </asp:MenuItem>
                    <asp:MenuItem Text="Help" NavigateUrl="#" />
                    <asp:MenuItem Text="Nothing" />
                </Items>
            </jk:BootstrapMenu>
        </div><!--/.nav-collapse -->
    </div>
</div>

Here’s the HTML markup view for using with a SiteMapDataSource:

<div class="navbar navbar-inverse navbar-static-top" role="navigation">
    <div class="container" style="padding: 0; margin: 0;">
        <div class="navbar-header">
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
        </div>
        <div class="navbar-collapse collapse">
            <jk:BootstrapMenu ID="BootstrapMenu2" runat="server" DataSourceId="SiteMapDataSource1" />
            <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" ShowStartingNode="False" />
        </div><!--/.nav-collapse -->
    </div>
</div>

In either case you’ll need a page directive

<%@ Register tagPrefix="jk" assembly="JK.Core.Web" namespace="JK.Core.Web.Controls" %>

Here’s the entire code for the class:

using System;
using System.ComponentModel;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace JK.Core.Web.Controls
{
    [ControlValueProperty("SelectedValue")]
    [DefaultEvent("MenuItemClick")]
    [SupportsEventValidation]
    [ToolboxData("<{0}:BootstrapMenu runat=\"server\"></{0}:BootstrapMenu>")]
    public sealed class BootstrapMenu : Menu
    {
        public override void RenderBeginTag(HtmlTextWriter writer)
        {
            // don't call base.RenderBeginTag()
        }

        public override void RenderEndTag(HtmlTextWriter writer)
        {
            // don't call base.RenderEndTag()
        }

        protected override void OnPreRender(EventArgs e)
        {
            // don't call base.OnPreRender(e);
            this.EnsureDataBound();
        }

        protected override void Render(HtmlTextWriter writer)
        {
            this.BuildItems(writer, this.Items, true);
        }

        protected override void EnsureDataBound()
        {
            base.EnsureDataBound();
        }

        private void BuildItems(HtmlTextWriter writer, MenuItemCollection items, bool isRoot = false)
        {
            if (items.Count <= 0)
            {
                return;
            }

            string cssClass = "dropdown-menu";

            if (isRoot)
            {
                cssClass = "nav navbar-nav";
                if (!string.IsNullOrEmpty(this.CssClass))
                {
                    cssClass += " " + this.CssClass;
                }
            }

            writer.AddAttribute(HtmlTextWriterAttribute.Class, cssClass);
            writer.RenderBeginTag(HtmlTextWriterTag.Ul);

            foreach (MenuItem item in items)
            {
                this.BuildItem(writer, item);
            }

            writer.RenderEndTag(); // </ul>
        }

        private void BuildItem(HtmlTextWriter writer, MenuItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            if (item.ChildItems.Count > 0)
            {
                writer.AddAttribute(HtmlTextWriterAttribute.Class, "dropdown");
            }

            writer.RenderBeginTag(HtmlTextWriterTag.Li);

            if (this.IsLink(item))
            {
                this.RenderLink(writer, item);
            }
            else if (this.HasChildren(item))
            {
                this.RenderDropDown(writer, item);
            }
            else
            {
                writer.RenderBeginTag(HtmlTextWriterTag.A);
                writer.Write(item.Text);
                writer.RenderEndTag();
            }

            writer.RenderEndTag(); // </li>
        }

        private bool HasChildren(MenuItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            return item.ChildItems.Count > 0;
        }

        private bool IsLink(MenuItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            return item.Enabled && !string.IsNullOrEmpty(item.NavigateUrl);
        }

        private void RenderLink(HtmlTextWriter writer, MenuItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            string href = !string.IsNullOrEmpty(item.NavigateUrl)
                    ? this.Page.Server.HtmlEncode(this.ResolveClientUrl(item.NavigateUrl))
                    : this.Page.ClientScript.GetPostBackClientHyperlink(
                        this,
                        "b" + item.ValuePath.Replace(this.PathSeparator.ToString(), "\\"),
                        true);
            writer.AddAttribute(HtmlTextWriterAttribute.Href, href);

            string toolTip = !string.IsNullOrEmpty(item.ToolTip)
                ? item.ToolTip
                : item.Text;
            writer.AddAttribute(HtmlTextWriterAttribute.Title, toolTip);

            writer.RenderBeginTag(HtmlTextWriterTag.A);
            writer.Write(item.Text);
            writer.RenderEndTag(); // </a>
        }

        private void RenderDropDown(HtmlTextWriter writer, MenuItem item)
        {
            if (item == null)
            {
                throw new ArgumentNullException("item");
            }

            if (writer == null)
            {
                throw new ArgumentNullException("writer");
            }

            writer.AddAttribute(HtmlTextWriterAttribute.Href, "#");
            writer.AddAttribute(HtmlTextWriterAttribute.Class, "dropdown-toggle");
            writer.AddAttribute("data-toggle", "dropdown");
            writer.RenderBeginTag(HtmlTextWriterTag.A);

            string anchorValue = item.Text + "&nbsp;";
            writer.Write(anchorValue);

            writer.AddAttribute(HtmlTextWriterAttribute.Class, "caret");
            writer.RenderBeginTag(HtmlTextWriterTag.B);
            writer.RenderEndTag(); // </b>

            writer.RenderEndTag(); // </a>

            this.BuildItems(writer, item.ChildItems);
        }
    }
}

Link: CodePlex Class Source Link
Link: CodePlex Sample Page Source
Link: Sample Project (zip)

Updates:

  • 2015 January 19: Added zip file sample project for download to OneDrive.
  • 2014 August 15: Added page directive needed to use control in page markup
  • 2014 April 11: Updated to work with SiteMapDataSource