Accessing a Dictionary Using Multiple Keys

Dictionaries and some other collection objects allow you to store an item along with a key value. This allows you to retrieve the item later, either by position or by key value. This code stores a value under the key "PHVIS," and finishes by setting the variable Result to "Peter Vogel":

Dim Items As New Dictionary(Of String,  String)
Items.Add("PHVIS", "Peter  Vogel")
Dim Result As String
Result = Items("PHVIS")  

But what if you want to store something by two values -- storing sales amounts by CustomerName and SaleDate, for instance? You could just concatenate two values together to create a single key, but a better solution would be to define a class to hold the two values to use as the key. Unfortunately, using a class won't work. When testing for equality, these collections will use an object's hashcode, returned from the class' GetHashCode method, to determine if two objects are identical. Two different objects, even if they're from the same class and have identical values in their properties, are considered to be different under this test.

But if you use a Structure instead,, everything works. Structures are scalar types rather than reference types like objects, so their values are compared to determine equality. A structure to hold two values might look like this:

Structure TwoValue
  Public CustomerId As String
  Public SaleDate As DateTime
End Structure

To use this structure, you might store a customer's sales under the customer's identifier, and the date that the sale was made:

Dim Items As New Dictionary(Of TwoValue, Integer)
Dim Key As TwoValue
Key.CustomerId = "A123"
Key.SaleDate =  Date.Parse("11/01/2010")
Items.Add(Key, 132)

Retrieving the value just consists of assembling a matching key and passing the key to the Dictionary. This example will retrieve the value and puts it in the variable Result: 

Dim Result As Integer
Dim Key2 As TwoValue
Key2.CustomerId = "A123"
Key2.SaleDate =  Date.Parse("11/01/2010")

Result = items(Key2)

Posted by Peter Vogel on 04/04/2012 at 1:16 PM5 comments


Stop Scanning Solution Explorer for Your Files

If you scroll up and down through Solution Explorer looking for files in long list -- stop! Did you know that Solution Explorer acts like a searching list? For instance, if you type the same letter over and over again, Solution Explorer will scroll through all the folders and files with names that begin with that letter. So instead of hitting the same letter again and again, you type different letters, Solution Explorer assumes that you're typing the file name and will scroll to the file with that name.

Solution Explorer will even leap over project boundaries and burrow into Solution folders to find the file whose name you're typing. The only downside is that Solution Explorer only searches the items you can see in Solution Explorer; it won't expand collapsed files, folders, projects, or Solution folders.

Posted by Peter Vogel on 04/01/2012 at 1:16 PM2 comments


Free Tool: Replace NotePad with NotePad2

Like last month's free tool, this month's tool isn't really a .NET-specific tool. However, I can't program without NotePad (though it was a long time ago when I did the XML schemas for a major software developer's products and my primary tools were NotePad and Internet Explorer). At the very least I often find myself using NotePad whenever I want to look at some code from Windows Explorer and don't want to start up Visual Studio.

I've used a couple of NotePad replacements (TextPad for the longest time) but my current favorite is NotePad2 by Florian Balmer. I like that it's fast to start up and load a file while still doing everything Notepad does. But I also like that it does code highlighting, will generate autoclose tags for XML and HTML, has a recent files list, and will minimize to the tray (so it's ready for all the other things that I use it for). A tool like NotePad2 is always going to be a trade-off: I'm looking for a speedy tool but I also want lots of functionality. NotePad2 hits the sweet spot for me.

If you try it and like it, you can have NotePad2 replace NotePad with a tweak to the Windows registry. You can even have NotePad2 support Windows 7's jump list of recently accessed files with a few more tweaks (and did I mention that NotePad2 has a Favorites list where you can add files you return to repeatedly?). Scott Hanselman's blog at has links to descriptions of how to get NotePad2 to replace NotePad (including how to get NotePad2 to support Window 7's jump list of recently accessed files).

Posted by Peter Vogel on 03/28/2012 at 1:16 PM3 comments


Guru Tip: Avoid the HTML5 FOUJUI Experience

As I continue to incorporate more JavaScript into my applications and, especially, as I try to leverage the new JavaScript/HTML 5 technologies, I'm discovering a new problem: It's now possible for users to see raw, uninitialized HTML in their browser before my JavaScript properly arranges things. I asked Todd Anglin, VP for HTML5 Web & Mobile Tools at Telerik, if there was a solution to this problem. Here's what he said:

This is a new problem that can ruin the fancy, new experience of your HTML5 app. I think of it as FOUJI, or Flash of Uninitialized JavaScript UI: Users see the ugly HTML briefly and then, suddenly, the page looks right. One solution for this problem is to use a JavaScript loading screen that "hides" the page HTML as it initializes.

For instance, this HTML displays some gif (probably animated) that lets users know that their page is being prepared:

<div id="preLoad">
  <div>
    <img src="styles/BlueOpal/loading-image.gif"  alt="Loading Image"
 style="width:48px;" />
    <br />Loading...
  </div>
</div>
I use it with this CSS:
#preLoad{            
    width:100%;
    height:100%;
    background:#FFF;
    position:absolute;
    top:0;    
}        
 
#preLoad div{
    position:absolute;
    top: 50%;
    left: 50%;
    height:60px;
    margin-top: -30px;
    margin-left: -24px;
}

To make the loading screen "go away" when I've finished setting it up, I trigger a new event when the JavaScript that initializes my page is complete:

$(document).trigger("APP_READY");
In my main page, I wire up code to that event to hide my loading screen:
$(document).bind("APP_READY",function(){ 
    $("#preLoad").fadeOut(); 
});

Now users see the loading screen until my app finishes initializing. Then the loading screen fades out to reveal the UI -- without FOUJUI.

The richness of HTML5 Web apps is great, but it includes extra challenges like FOUJUI as you make the transition to the client. One of the things that we're doing with the Kendo UI is provide another solution: server-side helpers that render the HTML on the server before sending it to the user. In the meantime, you have to check your apps for any unintended flashing.

Todd had more to say on improving this solution (including incorporating CSS3 Transitions) on his blog.

Posted by Peter Vogel on 03/25/2012 at 1:16 PM11 comments


Use PreviousPageType to Simplify Page Data Access

(Editor's Note: This article has been updated to correct errors in the code.)

In an earlier post on cross-page posting, a reader pointed out that I hadn't discussed the PreviousPageType directive, which can eliminate the need for using the awkward FindControl method (for more on the difficulties of using FindControl -- especially with pages using a Master Page -- see one of the first Practical ASP.NET columns I wrote). Here's how to use PreviousPageType.

In ASP.NET you can request another page either through cross-page posting, or through a Server.Transfer from the code in a different page and then accessing the original page from code in the new page. Let's call the page that makes the request the "source page" and call the requested page the "target page". In the Target page, you can use the Page's PreviousPage property to access the source page as an object, like this:

 
Dim pg As Page
pg = Me.PreviousPage

As my reader suggested, in the source page you can declare a public property that grabs a result from a control on the source page. This property, for instance, returns the Text property of a control called CustomerIDTextBox:

Public ReadOnly Property Customer() As String
    Get
      Return Me.CustomerIDTextBox.Text
    End Get
  End Property

However, the PreviousPage property returns a Page object; so, to access this property in the target page, you need to cast the PreviousPage property to the source page's type. Assuming that my source page is called Source.aspx, that code would look like this:

Dim CustomerID As String
CustomerID = CType(Me.PreviousPage, Source).CustomerID

If, as my reader points out, you know which page is going to be the source page, you can pass that information onto ASP.NET by adding the PreviousPageType directive to the aspx file of the target page. Since my source page is called Source.aspx, the directive in the target page that specifies the previous page would look like this:

<%@ Page  Language="VB" …
<%@  PreviousPageType VirtualPath="Source.aspx" %> 

This allows ASP.NET to strongly type the PreviousPage property in the target page. The code in my target page that accesses the property in the source page would now look like this:

Dim CustomerID As String
CustomerID = Me.PreviousPage.CustomerID

Posted by Peter Vogel on 03/12/2012 at 1:16 PM0 comments


Free Tool: A Better Visual Studio Command Prompt with Console 2.0

Console 2.0 was created by Marko Bozikovic. OK, it isn't a .NET Framework development tool, but I love it. Console is everything that the Windows or Visual Studio Command Prompt should be. Thanks to growing up in MS-DOS I know all the tricks in the console window (how to paste text from other windows, how to scroll up and edit previous commands), but Console is just so much better than knowing those tricks that I happily abandoned them. Console 2.0 provides multiple tabbed windows (so you can work on more than one problem at once), a much easier copy-and-paste process, and the ability to resize it horizontally to reduce line wrap.

It doesn't take long to set Console up to work as your Visual Studio Command Prompt -- just copy the settings from the VS Command Prompt shortcut in your Start Menu to the Shell and Startup dir: entries in Console's Edit | Settings dialog. You can also customize the number of columns Console displays, the font its uses, and its colors (among other choices). Other than setting Console up to work as my Visual Studio Command Prompt, the only other customization I made was to remove the requirement to hold down the shift key while dragging my mouse to select text.

Posted by Peter Vogel on 02/28/2012 at 1:16 PM2 comments


Organize Big Solutions with Solution Folders

If you have a solution that contains multiple projects (I had one solution with 14 projects), you should probably be using Solution Folders. Solution Folders recognize that the projects in a solution often belong in groups: keeping the Web projects separate from the middle-tier business projects, or keeping a class library close to its test project. Solution Folders let you make those groups explicit in Solution Explorer.

To add a Solution Folder to Solution Explorer, right-click on the Solution line at the top and select Add | New Solution Folder. This will add the folder and let you name it. After you've added your Solution Folder, you can drag projects already in Solution Explorer into the folder. You can then expand or collapse each Solution Folder, or even unload a folder if you don't need that part of solution right now and don't want to waste time rebuilding those projects. You can also right-click on a Solution folder and pick Build to compile just the projects in that folder.

This isn't a feature that you need if you keep the number of projects in a solution small; but once you pass some threshold number of projects (and that number will vary from one developer to another), you'll be glad it's there.

Posted by Peter Vogel on 02/24/2012 at 1:16 PM1 comments


Guru Tips: Making ToString Useful, Plus Not Getting Fooled by Closure

Julian Bucknall is the Chief Technology Officer at DevExpress. I asked him if he had a tip for .NET developers. Julian said he had two (and that doesn't count the bonus he threw in).

First Tip: ToString() is your friend. When the CLR team wrote System.Object, they included the very minimum of methods needed for all objects. All of them are 100 percent vital, no fat here. One of them is ToString(), the method that provides a human-readable string of the important properties in your class -- especially important for debugging. The default is boring and uninformative: you should work on creating your own overrides for your own classes. Your fellow developers will thank you, since they won't have to go spelunking through your class' properties when debugging -- they can just call your ToString method.

Bonus Asp.Net Tip: Do the same with the toString method for your prototypes in JavaScript. Much more informative than getting back the default "[object Object]'.

Second tip: Closures capture variables, not values. Writing anonymous functions is great fun, but beware: If an anonymous function captures a local variable, it captures the variable, not the current value of that variable at the time the anonymous function is defined.

This code has two anonymous functions, both of which use the variable called constantValue. The code sets constantValue before defining each function, but, when the functions are executed it's the latest value of constantValue that's used:

delegate int AddConst(int x);
  
  class Program {
    static void Main(string[] args) {


      var constantValue = 7;
      AddConst AddSeven = (x) => { return x + constantValue; };


      constantValue = 2;
      AddConst AddTwo = (x) => { return x + constantValue; };


      Console.WriteLine(AddSeven(4)); // result: 6 !?!
      Console.WriteLine(AddTwo(4));   // result: 6

      Console.ReadLine();
    }
  }

Here, the AddSeven and AddTwo functions aren't capturing the current value of constantValue when the functions are created; they're capturing the variable. When the functions are run, they use whatever the value of currentValue is at the time of execution. Beware!

Posted by Peter Vogel on 02/16/2012 at 1:16 PM1 comments


Using Dynamic Classes to Pass Data

In an earlier tip on using tuples to return multiple values from a method, several readers noted that the tuple's property names (Item1, Item2) left a lot to be desired -- you couldn't really call those names "self-documenting". As a fan of Really Obvious Code (ROC Rocks!), I should point out that there's a solution: using a Dynamic class. As with tuples, the goal here is to create a way to return multiple values from a method without defining a whole new class with its attendant properties and then using that class in exactly one place (returning values from a method) for just a few milliseconds.

A dynamic class lets you add properties to a class without defining them beforehand, as in this example which defines the variable returnClass as dynamic and then adds a CustomerID and Age property to it just by setting values on those properties:

private dynamic GetCustomerInfo()
  {
    dynamic returnClass;
    returnClass.CustomerID = "A123";
    returnClass.Age = 21;
    return returnClass;
  }

To call this method, accept the class, and access the properties, you'd write code like this:

 
dynamic aClass;
aClass = GetCustomerInfo();
this.CustIdTextBox.Text = aClass.CustomerID;

What you give up with Dynamic classes is IntelliSense: when accessing the properties on aClass, IntelliSense won't provide the list of property names for the class. However, compared to using tuples (with the distinctly unhelpful names Item1, Item2 and so on), that's not a real loss. What you do lose that you may care about, however, is compile-time type safety: if you set a dynamic property to a string and then attempt to move the value into an integer variable, you won't find about your problem until the code executes at runtime.

As another reader pointed out in that original column, neither technique is a good choice for a public interface, but worth considering when you have two private methods interacting.

Posted by Peter Vogel on 02/13/2012 at 9:03 AM6 comments


Creating a Useful Task List in Visual Studio

What developers like to do best is to write code (and design the applications that will let them right code). Administrative overhead just gets in the way of writing code—even something as simple as a To Do list. Yet developers are constantly getting part way through a problem and having to go and work on something else, or to address another part of the application before returning to finish what they were working on.

The Visual Studio Task List actually helps with this. Just type a comment that begins with ToDo (e.g. 'ToDo or //ToDo) and is followed by some text, and a line with your text appears in the Task List. To see the Task List, from the View menu, and select Task List. When the Task List window displays, switch the drop down list at its top to Comments. Once you see the list of notes that you (or someone else) has left on the Task List, double-clicking on an item in the list takes you to that section of your application.

In addition to ToDo, there are two other tokens: HACK (for…) and UNDONE (for…). However, if you (or your team) wants to mark additional types of material, you can create your own custom tokens. Select Options From the Tools menu, and in the Options dialog, expand the Environment node to find the Task List entry. Enter a name for your token in the Name text box and click the Add button to define your token (if your token will be used in a case-sensitive language, make life easy for the token's users by making the name either all uppercase or all lowercase).

Unfortunately, there's no easy way to share custom tokens among a team. You can export your settings (which include custom tokens) into a file so that other developers can import your custom tokens…but it's probably just as easy for each developer to set up any new tokens you invent in their copy of Visual Studio (besides, then the developer will know what tokens are available).

Visual Studio 2010 displays all your tokens when you open a project -- earlier versions wouldn't populate the Task List until you opened the file containing the token. However, in earlier versions of Visual Studio, if you do a Find and Replace replacing "ToDo" with "ToDo" and click the Replace All button, Visual Studio would find all of the files containing a ToDo token and open them for you, updating the Task List as it goes.

Posted by Peter Vogel on 01/30/2012 at 9:03 AM1 comments


Free Tool: Beyond Testing with Browsers

In a previous free tool column, I recommended WoVS Default Browser Switcher, which provides an easy way to change your default browser when testing ASP.NET pages. However, browsers are only one kind of user agent that can access your page (I do some search engine optimization work -- primarily for professional companies like law firms -- so working with search agents is important to me).

In a Practical .NET column, I discussed Microsoft's recent updating of the file that ASP.NET uses to determine the capabilities of the browser requesting your site and how you could mock that component to test against how your site behaves with different user agents.

My friend Kevin Rattan (who writes on Learning Tree's Perspectives on Programming in .NET) pointed out a cool tool: Chris Pederick's User Agent Switcher. User Agent Switcher is a Firefox add-in that basically causes Firefox to lie about itself and represent itself as a different browser…or even as a search  'bot or an iPhone. It adds a new menu and toolbar button to Firefox to let you change how Firefox represents itself to your server. You can either switch Visual Studio over to using Firefox for testing, or just keep Firefox open and aimed at your site to see your site as a search 'bot sees it.

Posted by Peter Vogel on 01/30/2012 at 1:16 PM0 comments


ASP.NET: Integrating Search and Help with Cross-Page Posting

By default, ASP.NET pages post their data back to themselves. However, there are cases that, when the user clicks on a button, you want the data in the browser sent to some other page. For instance, if you have an option that lets users search the site, you've probably implemented this with a Search button with a text box on every page on your site. When the user enters some text and clicks on the button, you want to send the user to your site's Search page, not back to the current page—and you also want to send to that page whatever search term the user entered in the text box beside the button. The same is true of a Help button with a text box: When the user clicks the button, you want to send the user to a page that displays help about the topic the user entered into the text box.

In ASP.NET, sending the data on a page to another page is called cross-page posting. It's controlled through a property on the ASP.NET Button. To turn on cross-page posting, set the button's PostBackUrl property to the URL of the page you want the data sent to (e.g., your search or help page).

However, when you arrive at the other page, you'll need to retrieve the value that the user entered in the search or help text box. Since you're now on a different page, the user's data won't be nicely slotted into a control on the form—you'll have to hunt for the text box. And, since the user can come to a page through many ways (the user may have bookmarked your search page, for instance, and used the bookmark to get to the page) you don't want to hunt for the text box unless you know it's there.

The Page Load event is a good place to put that code. You should begin by determining if the user has arrived at your page through cross-page posting. The first step is to check to see if the page's PreviousPage property is set: If the user came to your page through cross-page posting,  PreviousPage will be set to something.

However, PreviousPage will be set in at least two scenarios: if the user arrived at the page using cross-page posting, or if the user arrived through using Server.Transfer. So, once you know that the PreviousPage property has something in it, you should check its IsCrossPagePostBack property to see if user got there through a click on a postback button. The code looks like this in Visual Basic:

If Me.PreviousPage IsNot Nothing AndAlso _
   Me.PreviousPage.IsCrossPagePostBack = True Then

The next step is to find your textbox. For that you can use the PreviousPage's FindControl method, passing the Id of the TextBox you're looking for. You'll need to cast the result to the correct object type (and you should also deal with not finding the text box in case some other developer builds a page that posts to your search or help page):

Dim txt As TextBox
  txt = CType(Me.PreviousPage.FindControl _
                         ("SearchTextBox"), TextBox)
  If txt IsNot Nothing Then  
      RetrievedString = txt.Text
  End If

Finding the text box is a little more difficult if your control is inside a naming container like a Content control or a FormView. It wouldn't be surprising if your cross-page posting button is part of your site's Master Page (a Help or Search button would, typically, be something that you'd want on every page on the site). Fortunately, you can search a PreviousPage's Master page through its Master property, like this:

Dim txt As TextBox
  txt = Me.PreviousPage.Master.FindControl( _
     "HelpTopicTextBox"), TextBox)

Posted by Peter Vogel on 01/13/2012 at 1:16 PM3 comments


Upcoming Events

.NET Insight

Sign up for our newsletter.

I agree to this site's Privacy Policy.