Setting the active link in a Twitter Bootstrap Navbar in ASP.NET MVC

If you have used Twitter Bootstrap before you will probably know that it has a Navbar component so you can easily build navigation for a website. One of the features of the Navbar is being able to set which of the links within it is the currently active one, so this can displayed to the user.

As the Navbar needs to appear on every page it would be placed into your _Layout.cshtml (assuming you’re using Razor) and would look something like this

 ...
 <div class="navbar navbar-fixed-top">
	<div class="navbar-inner">
		<div class="container">
			<a class="brand" href="#">Title</a>
			<ul class="nav">
				<li><a href="#">Link 1</a></li>
				<li><a href="#">Link 2</a></li>
				<li><a href="#">Link 3</a></li>
				<li><a href="#">Link 4</a></li>
			</ul>
		</div>
	</div>
</div>
...

So, how do you find out which is the active link and set the active class on the <li> tag? I’ve created an HtmlHelper extension method to do just that!

And it can be used like this:

...
<div class="navbar navbar-fixed-top">
	<div class="navbar-inner">
		<div class="container">
			<a class="brand" href="#">Title</a>
			<ul class="nav">
				@Html.MenuLink("Link 1","Index","Home")
				@Html.MenuLink("Link 2","Index","Home")
				@Html.MenuLink("Link 3","Index","Home")
				@Html.MenuLink("Link 4","Index","Home")
			</ul>
		</div>
	</div>
</div>
...

This will output a <li> tag with an anchor tag inside it and will add class=”active” to the <li> tag if it is the active one.
Note: depending on the namespace of your HtmlHelper extension class you may need to add a using statement to the top of the Razor file, such as

@using MyProject.Web.Helpers

XamDockManager – Setting keyboard focus back to the add row

For a project at work we needed the ability for the user to use the tab button on an Infragistics XamDataGrid to submit the record they are adding and set the focus back to the first cell of the data grid. For whatever reason this is not a built in method (have they not tried to do a lot of data entry?), so I came up with my own solution based on a post on the Infragistics forums.

I’ve included the gist below in case anyone else needs this ability (or can find a better way of doing it). You just need to add a PreviewKeyDown event handler to the grid, like below.

Entity Framework 4.3 – Adding Migrations from AppConfig in different project

When using the new Entity Framework migration features where your DbContext is not in the start up project for the solution you need to explicitly tell the Update-Database command which project to use to get the connection string information from. This can be done by passing a parameter to Update-Database called “StartupProjectName”, so the full command to run in the Package Manager Console is:

PM> Update-Database -StartupProjectName "MyProject.Shell"

PM> Update-Database -StartupProjectName "MyProject.Shell"

Make sure the default project is set to the project that contains your DbContext class.

One thing to note is that migrations will create your DbContext using the default constructor so a connection string name will need to be specified by calling the base constructor.

public class MyContext : DbContext
{
    public MyContext() :base("DefaultConnection"){ }
}

XamComboEditor / ComboEditorTool Setting Default Text

Want to have default text shown when no item is selected in a combo box, such as “Please Select”? This can easily be achieved using a binding converter such as:

	public class NullConverter : IValueConverter
	{
		public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			if (value == null)
			{
				return "Please Select";
			}
			else
			{
				return value;
			}
		}

		public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
		{
			if (value is string && ((string)value) == "Please Select")
			{
				return null;
			}
			else
			{
				return value;
			}
		}
	}

Then in your XAML it can be used like this:


<Window.Resources>
    <igEditors:ComboBoxItemsProvider  x:Key="ComboItemsProvider" ItemsSource="{Binding Path=Data}" />
    <local:NullConverter x:Key="nullConv" />
</Window.Resources>

<igEditors:XamComboEditor ItemsSource="{Binding Path=Data}"
                          Text="Please Select"
                          SelectedItem="{Binding Path=SelectedItem,Converter={StaticResource nullConv}}"/>

Empty WPF ListBox

I needed to show some text when a ListBox was empty, a quick Google turned up a StackOverflow question that was just the ticket!

Getting a .NET Color Name

I needed to find out the standard .NET colour name for for a Color object, assuming the Color object was a standard .NET colour! As there is no built in way of doing this I created a simple helper class, the code is below.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Media;

namespace Chris.Blog
{
	public static class ColorToName
	{
		private static Dictionary<string, Color> Colours = new Dictionary<string, Color>();

		static ColorToName()
		{
			System.Reflection.PropertyInfo[] pinfo = typeof(System.Windows.Media.Colors).GetProperties();
			
			foreach (var p in pinfo)
			{
				Colours.Add(p.Name,(Color)p.GetGetMethod().Invoke(null,null));
			}
		}

		public static string GetName(Color color)
		{
			if (!Colours.ContainsValue(color))
				throw new ArgumentOutOfRangeException("color", "Not a named WPF color");

			return Colours.First((c) => c.Value == color).Key;
		}
	}
}

Using XamDockManager with Caliburn.Micro

I asked a question on StackOverflow about using the Infragistics XamDockManger with Caliburn.Micro, Marco Amendola came up with several ways to do it and I chose to implement my own docking manager. If you want to skip my ramblings you can find the code on bitbucket or as an attachment to this post. You will need to add your own versions of InfragisticsWPF4.DockManager.v10.3.dll and InfragisticsWPF4.v10.3.dll, it will probably work with older versions as well, but I have not tested this.

My XamDockManagerDockAwareWindowManager class is heavily based on the code posted in a thread on the Caliburn.Micro discussion forum. The biggest difference between them is I had to create a XamDockManagerHelper class to create the necessary split panes, which Avalon Dock appears to do automatically. It is a simple class that checks the XamDockManager to see if a SplitPane has already been created for that required position, if so it returns it or creates a new one in the required position.

private static class XamDockManagerHelper
		{
			public static PaneLocation GetSplitPaneLocation(SplitPane pane)
			{
                return XamDockManager.GetPaneLocation(pane);
			}

			public static SplitPane FindSplitPaneWithLocation(XamDockManager dockManager,PaneLocation location)
			{
				return dockManager.Panes.FirstOrDefault(p => GetSplitPaneLocation(p) == location);
			}

			public static SplitPane FindSplitPaneWithLocationOrCreate(XamDockManager dockManager, InitialPaneLocation location)
			{
				return FindSplitPaneWithLocationOrCreate(dockManager,location.ToPaneLocation());
			}

			public static SplitPane FindSplitPaneWithLocationOrCreate(XamDockManager dockManager,PaneLocation location)
			{
				SplitPane pane = FindSplitPaneWithLocation(dockManager,location);

				if (pane != null)
					return pane;

				pane = new SplitPane();
				XamDockManager.SetInitialLocation(pane, location.ToInitialPaneLocation());

				return pane;
			}

			public static TabGroupPane FindTabGroupPane(XamDockManager dockManager)
			{
				TabGroupPane tabs;

				dockManager.TryFindChild<TabGroupPane>(out tabs);

				return tabs;
			}

		}

The code makes use of a couple of extension methods that convert between an InitialPaneLocation enum and a PaneLocation enum.

public static class PaneLocationEnum
	{
		public static InitialPaneLocation ToInitialPaneLocation(this PaneLocation location)
		{
			InitialPaneLocation initialPaneLocation;

			switch (location)
			{
				case PaneLocation.DockedLeft:
				case PaneLocation.DockedRight:
				case PaneLocation.DockedTop:
				case PaneLocation.DockedBottom:
				case PaneLocation.FloatingOnly:

					initialPaneLocation = (InitialPaneLocation)Enum.Parse(typeof(InitialPaneLocation), location.ToString());

					break;
				case PaneLocation.Floating: //DockableFloating
					initialPaneLocation = (InitialPaneLocation)Enum.Parse(typeof(InitialPaneLocation), "DockableFloating");
					break;

				case PaneLocation.Unpinned: //Not
				case PaneLocation.Document: //Not
				case PaneLocation.Unknown: //Not
					throw new InvalidOperationException("Can not convert PaneLocation to InitialPaneLocation");

				default:
					throw new ArgumentOutOfRangeException("location");
			}

			return initialPaneLocation;
		}

		public static PaneLocation ToPaneLocation(this InitialPaneLocation location)
		{
			PaneLocation paneLocation;

			switch (location)
			{
				case InitialPaneLocation.DockedLeft:
				case InitialPaneLocation.DockedTop:
				case InitialPaneLocation.DockedRight:
				case InitialPaneLocation.DockedBottom:
				case InitialPaneLocation.FloatingOnly:

					paneLocation = (PaneLocation) Enum.Parse(typeof (PaneLocation), location.ToString());

					break;
				case InitialPaneLocation.DockableFloating:

					paneLocation = (PaneLocation)Enum.Parse(typeof(PaneLocation), "Floating");

					break;
				default:
					throw new ArgumentOutOfRangeException("location");
			}

			return paneLocation;
		}
	}

The XamDockManger window manager class can be used in exactly the same way as the standard Caliburn.Micro window manager, here is the ShellViewModel from the example code.

 [Export(typeof(IShell))]
    public class ShellViewModel : Screen, IShell
    {

        private readonly IDockAwareWindowManager _windowManager;

        [ImportingConstructor]
        public ShellViewModel(IDockAwareWindowManager windowManager)
        {
            _windowManager = windowManager;
        }

        public void OpenDocked()
        {
            _windowManager.ShowDockedWindow(new DialogViewModel(), null, true, InitialPaneLocation.DockedLeft);
        }

        public void OpenFloating()
        {
            _windowManager.ShowFloatingWindow(new DialogViewModel());
        }

        public void OpenDocument()
        {
            _windowManager.ShowDocumentWindow(new DialogViewModel());
        }

    }

You can find the complete code on bitbucket or as an attachment to this post, I expect the code can be improved in many ways but I hope that it helps someone!

Debugging WPF Bindings

A very handy guide to debugging WPF bindings.

ConfigurationManager Wrapper for Unit Testing

Ever needed to unit test .NETs System.Configuration.ConfigurationManager class? I had to today so produced a wrapper class and interface to make the task a bit easier.

using System.Configuration;

namespace Chris.Blog
{
	public interface IConfigurationManager
	{
		/// <summary>
		/// Gets the System.Configuration.AppSettingsSection data for the current application's default configuration.
		/// </summary>
		/// <returns>Returns a System.Collections.Specialized.NameValueCollection object that contains the contents of the System.Configuration.AppSettingsSection object for the current application's default configuration.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		System.Collections.Specialized.NameValueCollection AppSettings { get; }

		/// <summary>
		/// Gets the System.Configuration.ConnectionStringsSection data for the current application's default configuration.
		/// </summary>
		/// <returns>Returns a System.Configuration.ConnectionStringSettingsCollection object that contains the contents of the System.Configuration.ConnectionStringsSection object for the current application's default configuration.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		ConnectionStringSettingsCollection ConnectionStrings { get; }

		/// <summary>
		/// Retrieves a specified configuration section for the current application's default configuration.
		/// </summary>
		/// <param name="sectionName">The configuration section path and name.</param>
		/// <returns>The specified System.Configuration.ConfigurationSection object, or null if the section does not exist.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		object GetSection(string sectionName);

		/// <summary>
		/// Retrieves a specified configuration section for the current application's default configuration.
		/// </summary>
		/// <typeparam name="T">The type to cast the return value to.</typeparam>
		/// <param name="sectionName">The configuration section path and name.</param>
		/// <returns>The specified System.Configuration.ConfigurationSection object, or null if the section does not exist.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		/// <exception cref="System.InvalidCastException">The section could not be cast to an object of type <typeparamref name="T"/>.</exception>
		T GetSection<T>(string sectionName);

		/// <summary>
		/// Opens the configuration file for the current application as a System.Configuration.Configuration object.
		/// </summary>
		/// <param name="userLevel">The System.Configuration.ConfigurationUserLevel for which you are opening the configuration.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		Configuration OpenExeConfiguration(ConfigurationUserLevel userLevel);

		/// <summary>
		/// Opens the specified client configuration file as a System.Configuration.Configuration object.
		/// </summary>
		/// <param name="exePath">The path of the configuration file. The configuration file resides in the same directory as the executable file.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		Configuration OpenExeConfiguration(string exePath);

		/// <summary>
		/// Opens the machine configuration file on the current computer as a System.Configuration.Configuration object.
		/// </summary>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		Configuration OpenMachineConfiguration();

		/// <summary>
		/// Opens the specified client configuration file as a System.Configuration.Configuration object that uses the specified file mapping and user level.
		/// </summary>
		/// <param name="fileMap">An System.Configuration.ExeConfigurationFileMap object that references configuration file to use instead of the application default configuration file.</param>
		/// <param name="userLevel">The System.Configuration.ConfigurationUserLevel object for which you are opening the configuration.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel);

		/// <summary>
		/// Opens the machine configuration file as a System.Configuration.Configuration object that uses the specified file mapping.
		/// </summary>
		/// <param name="fileMap">An System.Configuration.ExeConfigurationFileMap object that references configuration file to use instead of the application default configuration file.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap);

		/// <summary>
		/// Refreshes the named section so the next time that it is retrieved it will be re-read from disk.
		/// </summary>
		/// <param name="sectionName">The configuration section name or the configuration path and section name of the section to refresh.</param>
		void RefreshSection(string sectionName);
	}
}

using System.Configuration;

namespace Chris.Blog
{
	public class ConfigurationManagerWrapper : IConfigurationManager
	{
		/// <summary>
		/// Retrieves a specified configuration section for the current application's default configuration.
		/// </summary>
		/// <param name="sectionName">The configuration section path and name.</param>
		/// <returns>The specified System.Configuration.ConfigurationSection object, or null if the section does not exist.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public object GetSection(string sectionName)
		{
			return ConfigurationManager.GetSection(sectionName);
		}
		
		/// <summary>
		/// Retrieves a specified configuration section for the current application's default configuration.
		/// </summary>
		/// <typeparam name="T">The type to cast the return value to.</typeparam>
		/// <param name="sectionName">The configuration section path and name.</param>
		/// <returns>The specified System.Configuration.ConfigurationSection object, or null if the section does not exist.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		/// <exception cref="System.InvalidCastException">The section could not be cast to an object of type <typeparamref name="T"/>.</exception>
		public T GetSection<T>(string sectionName)
		{
			return (T)ConfigurationManager.GetSection(sectionName);
		}

		/// <summary>
		/// Opens the specified client configuration file as a System.Configuration.Configuration object.
		/// </summary>
		/// <param name="exePath">The path of the configuration file. The configuration file resides in the same directory as the executable file.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public Configuration OpenExeConfiguration(string exePath)
		{
			return ConfigurationManager.OpenExeConfiguration(exePath);
		}

		/// <summary>
		/// Opens the configuration file for the current application as a System.Configuration.Configuration object.
		/// </summary>
		/// <param name="userLevel">The System.Configuration.ConfigurationUserLevel for which you are opening the configuration.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public Configuration OpenExeConfiguration(ConfigurationUserLevel userLevel)
		{
			return ConfigurationManager.OpenExeConfiguration(userLevel);
		}

		/// <summary>
		/// Opens the machine configuration file on the current computer as a System.Configuration.Configuration object.
		/// </summary>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public Configuration OpenMachineConfiguration()
		{
			return ConfigurationManager.OpenMachineConfiguration();
		}

		/// <summary>
		/// Opens the specified client configuration file as a System.Configuration.Configuration object that uses the specified file mapping and user level.
		/// </summary>
		/// <param name="fileMap">An System.Configuration.ExeConfigurationFileMap object that references configuration file to use instead of the application default configuration file.</param>
		/// <param name="userLevel">The System.Configuration.ConfigurationUserLevel object for which you are opening the configuration.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public Configuration OpenMappedExeConfiguration(ExeConfigurationFileMap fileMap, ConfigurationUserLevel userLevel)
		{
			return ConfigurationManager.OpenMappedExeConfiguration(fileMap, userLevel);
		}

		/// <summary>
		/// Opens the machine configuration file as a System.Configuration.Configuration object that uses the specified file mapping.
		/// </summary>
		/// <param name="fileMap">An System.Configuration.ExeConfigurationFileMap object that references configuration file to use instead of the application default configuration file.</param>
		/// <returns>A System.Configuration.Configuration object.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public Configuration OpenMappedMachineConfiguration(ConfigurationFileMap fileMap)
		{
			return ConfigurationManager.OpenMappedMachineConfiguration(fileMap);
		}

		/// <summary>
		/// Refreshes the named section so the next time that it is retrieved it will be re-read from disk.
		/// </summary>
		/// <param name="sectionName">The configuration section name or the configuration path and section name of the section to refresh.</param>
		public void RefreshSection(string sectionName)
		{
			ConfigurationManager.RefreshSection(sectionName);
		}

		/// <summary>
		/// Gets the System.Configuration.AppSettingsSection data for the current application's default configuration.
		/// </summary>
		/// <returns>Returns a System.Collections.Specialized.NameValueCollection object that contains the contents of the System.Configuration.AppSettingsSection object for the current application's default configuration.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public System.Collections.Specialized.NameValueCollection AppSettings
		{
			get
			{
				return ConfigurationManager.AppSettings;
			}
		}

		/// <summary>
		/// Gets the System.Configuration.ConnectionStringsSection data for the current application's default configuration.
		/// </summary>
		/// <returns>Returns a System.Configuration.ConnectionStringSettingsCollection object that contains the contents of the System.Configuration.ConnectionStringsSection object for the current application's default configuration.</returns>
		/// <exception cref="System.Configuration.ConfigurationErrorsException">A configuration file could not be loaded.</exception>
		public ConnectionStringSettingsCollection ConnectionStrings
		{
			get
			{
				return ConfigurationManager.ConnectionStrings;
			}
		}
	}
}