Generic Recursive Find Control Extension

Earlier today I posted about a Recursive Find Control Extension Method. Since then, I was informed by Steve Smith that I should check out the generic find control method which Aaron Robson has on his blog. He has some pretty nice methods there, so I just adapted them to be extension methods now. As extension methods the code looks like this.

/// <summary>
/// Similar to Control.FindControl, but recurses through child controls.
/// </summary>
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
    T found = startingControl.FindControl(id) as T;
 
    if (found == null)
    {
        found = FindChildControl<T>(startingControl, id);
    }
 
    return found;
}
 
/// <summary>     
/// Similar to Control.FindControl, but recurses through child controls.
/// Assumes that startingControl is NOT the control you are searching for.
/// </summary>
public static T FindChildControl<T>(this Control startingControl, string id) where T : Control
{
    T found = null;
 
    foreach (Control activeControl in startingControl.Controls)
    {
        found = activeControl as T;
 
        if (found == null || (string.Compare(id, found.ID, true) != 0))
        {
            found = FindChildControl<T>(activeControl, id);
        }
 
        if (found != null)
        {
            break;
        }
    }
 
    return found;
}

And this new extension method is called very similarly to how we called the previous code. It is called using the following code.

Label theOtherLabel = LoginView1.FindControl<Label>("OtherControlToFind");
if (theOtherLabel != null)
{
    theOtherLabel.Text = "Found this one also!";
}

It is able to find the Label inside of the the following LoginView.

<asp:LoginView ID="LoginView1" runat="server">
    <LoggedInTemplate>
        <asp:Panel ID="Panel1" runat="server">
            <asp:Panel ID="Panel2" runat="server">
                <asp:Panel ID="Panel3" runat="server">
                    <asp:Panel ID="Panel4" runat="server">
                        <asp:Panel ID="Panel5" runat="server">
                            <asp:Label ID="ControlToFind" runat="server" Style="color: Red" />
                            <asp:Label ID="OtherControlToFind" runat="server" Style="color: Blue" />
                            <asp:Label ID="AlwaysShow" runat="server" Text="This shows no matter what." />
                        </asp:Panel>
                    </asp:Panel>
                </asp:Panel>
            </asp:Panel>
        </asp:Panel>
    </LoggedInTemplate>
</asp:LoginView>

I've also updated my FindControl method so that is just an overload of the previous method. Since my extension method takes the same parameters and returns the same type as the existing find control method I needed to rename it FindControlR. I've now updated it so it takes an extra parameter, but doesn't have a different name. I've added a boolean "recurse" parameter. If this is set to false it just calls the standard FindControl method and if it is set to true it will recursively call itself finding the desired control.

This is the final product followed by how one would call it.

/// <summary>
/// Searches recursively in this control to find a control with the name specified.
/// </summary>
/// <param name="root">The Control in which to begin searching.</param>
/// <param name="id">The ID of the control to be found.</param>
/// <returns>The control if it is found or null if it is not.</returns>
public static Control FindControl(this Control root, string id, bool recurse)
{
    if (!recurse)
    {
        return root.FindControl(id);
    }
    System.Web.UI.Control controlFound; 
    if (root != null) 
    { 
        controlFound = root.FindControl(id);
        if (controlFound != null)
        {
            return controlFound;
        }
        foreach (Control c in root.Controls) 
        {
            controlFound = c.FindControl(id, true);
            if (controlFound != null)
            {
                return controlFound;
            }
        } 
    } 
    return null;
}
Label theLabel = LoginView1.FindControl("ControlToFind", true) as Label;
if (theLabel != null)
{
    theLabel.Text = "Found it!";
}

I hope everyone else sees the great value in extension methods.

See More Recent Projects in Visual Studio

I usually only open between 5 and 10 Visual Studio projects on a regular basis, so I love the recent projects section of the Visual Studio Start Page. The problem is that when I add projects to my solutions they get added into the recent projects window and it makes it so I now have to go get my solution open from the file system. This irritates me quite a bit.

So for anyone who wants to increase the Recent Projects section of the Visual Studio Start Page from this.

RecentProjectsSmall

To this!

RecentProjectsLarge

Just open up the Tools menu item at the top select options and follow the instructions on this nice screen shot.

RecentlyUsedItemListMenu

And enjoy not digging into the file system to get to that solution file.

Tests Not Executed In Test Results

Earlier today, as I was working with the Protégé I've been referring to previously, we were debugging some code, and we ran into a little bug. Our tests results would not execute. We tried restarting Visual Studio and a lot of other stuff and it didn't fix it. We eventually just restarted the machine, and that fixed the problem. We figured that even though it wasn't the most graceful solution, it is one we knew would work.

This is the error message we were receiving. None of our tests were executing and it wasn't very clear about why. We did figure out that it had to do with the code coverage we had previously been running.

TestResultsNotExecuted

These guys managed to recreate the same error a little later, and they found a solution. Here is the solution to this problem.

What is going on is that we enabled code coverage and then we decided to start debugging.

So we started debugging and clicked "OK" through the message about how it was going to disable code coverage because you can't have it enabled while debugging.

Then we hit a break point and decided to stop debugging. All is seemingly still working correctly.

We attempt to run the tests again. This is where the %#$^ hits the fan. Suddenly we get that error message listed above and we have no idea why. It just doesn't want to let us execute the tests no matter what we tried.

Those budding young developers, as I said, found the error again and that time decided to pursue it further and discovered the root of the problem as well as how to fix it.

There is a process called VSPerfMon which is running in the background and is preventing the tests from being executed. It is the program which is running in the background to keep track of code coverage, and if you stopped the execution in the middle of a test it doesn't close correctly. If you kill that process you will once again be able to run your tests. To kill it you can get into the task manager select it from the processes list and end the process.

Have fun testing your code with tests that actually run.

Visual Studio Keyboard Shortcuts Disabled in Code Snippets

Since Visual Studio 2008 came out I've been extremely impressed with the software. One shortcut which I believe probably exists in CodeRush and Resharper is the ability to find the using directive needed at any given time. in VS2008 you can press ctrl + . and a little menu will appear which will add using directives for you. This makes writing code so much easier, because I don't have to go to the top of my file to add using statements. I type the name of what I need, press ctrl + . and keep going. I also love using the shortcut snippets in Visual Studio.

These snippets allow me to quickly and easily write properties, for loops, etc. I pretty much use these snippets whenever I have one for the task. They only require you fill in the necessary fields. The problem is that when you are filling in the information for one of these snippets it disables keyboard shortcuts. I can no longer have it automatically add my using directive to the top of the file. It will not bring up the menu.

In order to get this functionality to work again I have to complete the code snippet I am working on and go back to what needed the namespace added to it. I am then able to use the shortcut to add in my using directive.

These are a few examples of snippets I use in Visual Studio. I've been using var a lot lately for my foreach loops since I don't have to worry about this issue with it, but I prefer to avoid var.

foreach (var item in collection)
{

}

for (int i = 0; i < length; i++)
{

}

using (resource)
{

}

Yes, I used a using statement in this example so I could write about using a using shortcut to generate a using statement which needs a using directive.

Perhaps Microsoft will fix this and allow the keyboard shortcuts to still work while using these snippets. Maybe some of the third party tools already get around this. Resharper? CodeRush? Anyone else?

Visual C# 2008 Keyboard Shortcut Reference

As I've said previously, I am working with developers who are just beginning to learn the tools of the trade. They have a long way to go working with plenty of applications. All people always have more they can learn, so I'll pass along a useful reference here. I found this great reference sheet from Microsoft that has a bunch of key-bindings for Visual C# 2008. It is a PDF poster you can use to reference different shortcuts available to you.

http://www.microsoft.com/downloads/details.aspx?familyid=e5f902a8-5bb5-4cc6-907e-472809749973&displaylang=en