Category Archives: Tips

A WPF Numeric Entry Control

image When WPF first shipped, there was a noticeable lack of certain controls we’ve become used to in Win32 and WinForms: Calendar, DateTimePicker, and NumericUpDown. WPF 4 adds Calendar and DatePicker, but not anything for numeric entry.

For my solution I wanted something that behaved very similarly to the WinForms NumericUpdown control.

Some of the specifications:

  1. Allows user to set Value, MaxValue, MinValue, Increment, and LargeIncrement.
  2. Text directly entered is limited to numbers
  3. Pasted text is not intercepted, but when the control has lost focus it will be validated and reset to the previous value if necessary
  4. Two buttons, for increment and decrement
  5. Holding down the buttons with the mouse causes the number to increment continuously
  6. Up and down increment and decrement by Interval
  7. Page Up and Page Down increment and decrement by LargeInterval
  8. This version only supports integers

Creating the control

To begin, create a new WPF project and add a new User Control called NumericEntryControl. This will create a pair of .cs and .xaml files.

In the XAML file, change the <Grid> root element to be a <DockPanel>.

 

<UserControl 
    x:Class="NumericEntryDemo.NumericEntryControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d"
    xmlns:my="clr-namespace:NumericEntryDemo" Width="200" Height="26">
 
    <DockPanel>
    </DockPanel>
</UserControl>

Before we add the controls, let’s add some properties to our user control to hold the values the controls will use. These are dependency properties in order to take advantage of all the WPF goodness like data binding and animation. Let’s also add standard .Net property wrappers.

 

public partial class NumericEntryControl : UserControl
{
    public static readonly DependencyProperty ValueProperty = 
        DependencyProperty.Register("Value",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(0));
 
    public static readonly DependencyProperty MaxValueProperty = 
        DependencyProperty.Register("MaxValue",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(100));
 
    public static readonly DependencyProperty MinValueProperty = 
        DependencyProperty.Register("MinValue",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(0));
 
    public static readonly DependencyProperty IncrementProperty = 
        DependencyProperty.Register("Increment", 
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(1));
 
    public static readonly DependencyProperty LargeIncrementProperty = 
        DependencyProperty.Register("LargeIncrement",
            typeof(Int32), typeof(NumericEntryControl),
            new PropertyMetadata(5));    
 
    public Int32 Value
    {
        get
        {
            return (Int32)GetValue(ValueProperty);
        }
        set
        {
            SetValue(ValueProperty, value);
        }
    }
    
    public Int32 MaxValue
    {
        get
        {
            return (Int32)GetValue(MaxValueProperty);
        }
        set
        {
            SetValue(MaxValueProperty, value);
        }
    }
    
    public Int32 MinValue
    {
        get
        {
            return (Int32)GetValue(MinValueProperty);
        }
        set
        {
            SetValue(MinValueProperty, value);
        }
    }
    
    public Int32 Increment
    {
        get
        {
            return (Int32)GetValue(IncrementProperty);
        }
        set
        {
            SetValue(IncrementProperty, value);
        }
    }
    
    public Int32 LargeIncrement
    {
        get
        {
            return (Int32)GetValue(LargeIncrementProperty);
        }
        set
        {
            SetValue(LargeIncrementProperty, value);
        }
    }
}

 

Creating an incrementing TextBox

Add a TextBox inside the <DockPanel> and bind its text to the value we created in our control:

<DockPanel d:LayoutOverrides="Width">
    <TextBox 
        x:Name="_textbox" 
        Margin="2,0" 
        Text="{Binding Value, 
            Mode=TwoWay, 
            RelativeSource={RelativeSource FindAncestor,
                AncestorLevel=1, 
                AncestorType={x:Type my:NumericEntryControl}}, 
            UpdateSourceTrigger=PropertyChanged}" 
        HorizontalAlignment="Stretch" 
        HorizontalContentAlignment="Right" 
        VerticalContentAlignment="Center" />
</DockPanel>

This will create a TextBox that sizes itself with its parent (a feature I wanted, but is not strictly necessary) and  its text will be bound to the Value in our UserControl.

Handling text input

It used to be that you pointed with a mouse and entered text with a keyboard. However, it is common now to enter text with a stylus, gestures, or some future method not invented yet. Thankfully, WPF supports generic text input handling so you don’t have to concern yourself with the specific hardware.

 

public NumericEntryControl()
{
   InitializeComponent();
 
   _textbox.PreviewTextInput += 
        new TextCompositionEventHandler(_textbox_PreviewTextInput);
}
 
void _textbox_PreviewTextInput(object sender, 
                   TextCompositionEventArgs e)
{
    if (!IsNumericInput(e.Text))
    {
        e.Handled = true;
        return;
    }
}
 
private bool IsNumericInput(string text)
{
    foreach (char c in text)
    {
        if (!char.IsDigit(c))
        {
            return false;
        }
    }
    return true;
}

This prevents anything except numbers from being entered, whether via character recognition or keyboard. It does not, however, prevent the user from pasting non-numeric text into the box. We’ll handle that later.

Validating Text input

It’s problematic to validate and correct user input as they are entering it. For example, if you set the MaxValue to 100, then every time you enter 1000, it jumps to 100, it can be jarring. It’s a similar situation with text pasted into the control. What the NumericUpDown control does is handle these sort of situations when the control loses focus.

To prepare for this, when the control gains focus, we need to save the last valid value so we have something to restore to.

When the control loses focus, we need to first verify that it is a number and if so, clip it to the bounds of our MinValue and MaxValue. If anything fails, set it back to the previous value.

 

public partial class NumericEntryControl : UserControl
{
    private int _previousValue = 0;
 
    public NumericEntryControl()
    {
        InitializeComponent();
 
        _textbox.PreviewTextInput += 
            new TextCompositionEventHandler(
                _textbox_PreviewTextInput);
        _textbox.GotFocus += 
            new RoutedEventHandler(_textbox_GotFocus);
        _textbox.LostFocus += 
            new RoutedEventHandler(_textbox_LostFocus);
    }
 
    void _textbox_GotFocus(object sender, RoutedEventArgs e)
    {
        _previousValue = Value;
    }
 
    void _textbox_LostFocus(object sender, RoutedEventArgs e)
    {
        int newValue = 0;
        if (Int32.TryParse(_textbox.Text, out newValue))
        {
            if (newValue > MaxValue)
            {
                newValue = MaxValue;
            }
            else if (newValue < MinValue)
            {
                newValue = MinValue;
            }                
        }
        else
        {
            newValue = _previousValue;
        }
        _textbox.Text = newValue.ToString();
    }
}

Handle arrow keys

Just because WPF can handle text input from a variety of sources in a hardware-agnostic way doesn’t mean we should ignore the particular strengths of the keyboard. Specifically, we should handle the up and down arrows.

 

public NumericEntryControl()
{
    ...
    _textbox.PreviewKeyDown += 
        new KeyEventHandler(_textbox_PreviewKeyDown);
}
 
void _textbox_PreviewKeyDown(object sender, KeyEventArgs e)
{
    switch (e.Key)
    {
        case Key.Up:
            IncrementValue();
            break;
        case Key.Down:
            DecrementValue();
            break;
        case Key.PageUp:
            Value = Math.Min(Value + LargeIncrement, MaxValue);
            break;
        case Key.PageDown:
            Value = Math.Max(Value - LargeIncrement, MinValue);
            break;
        default:
            //do nothing
            break;
    }
}
 
private void IncrementValue()
{
    Value = Math.Min(Value + Increment, MaxValue);
}
 
private void DecrementValue()
{
    Value = Math.Max(Value - Increment, MinValue);
}

IncrementValue() and DecrementValue() are pulled out as their own method because they’re used in the button-handling code as well (see below).

The code so far is a perfectly usable textbox that accepts only numbers and can be incremented using the keyboard. Typically, however, we also need to support the mouse, and for that we need buttons (unless you want to do something exotic like programs like Photoshop and Lightroom do, where text boxes have support for incrementing gestures—that’s another article).

A button you can hold down

Adding buttons to increment once per click is pretty easy, but we really want to be able to hold down the buttons and have the TextBox increment. Let’s start by adding the XAML for the buttons:

 

<UserControl 
    x:Class="NumericEntryDemo.NumericEntryControl"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
    mc:Ignorable="d"
    xmlns:my="clr-namespace:NumericEntryDemo" 
    Width="200" Height="26"
    >
    <DockPanel d:LayoutOverrides="Width">
        <Button x:Name="buttonDecrement" 
                DockPanel.Dock="Left"
                Content="-" 
                Width="{Binding ActualHeight, 
                    ElementName=buttonDecrement, Mode=Default}" 
                Height="{Binding ActualHeight, 
                    ElementName=_textbox, Mode=Default}"/>
        <Button x:Name="buttonIncrement" 
                DockPanel.Dock="Right" 
                Content="+" 
                Width="{Binding ActualHeight, 
                    ElementName=buttonDecrement, Mode=Default}" 
                Height="{Binding ActualHeight, 
                    ElementName=_textbox, Mode=Default}"/>
        <TextBox 
            x:Name="_textbox" 
            Margin="2,0" 
            Text="{Binding Value, 
                Mode=TwoWay, 
                RelativeSource={RelativeSource FindAncestor,
                    AncestorLevel=1, 
                    AncestorType={x:Type my:NumericEntryControl}}, 
                UpdateSourceTrigger=PropertyChanged}" 
            HorizontalAlignment="Stretch" 
            HorizontalContentAlignment="Right" 
            VerticalContentAlignment="Center" />
    </DockPanel>
</UserControl>

Note that the button Width property is  bound to its own ActualHeight property, and the Height property is bound to the TextBox’s ActualHeight. This has the effect of keeping the buttons square, the same height as the TextBox. It’s an effect I wanted, but you can easily dispose of it. With these buttons, our control finally takes shape:

image

How fast should we increment?

Before writing the code to do the incrementing as we hold the button down, it’s worth considering how fast the incrementing should occur. Ideally, we would want it to increment at about the same rate as if we were holding down the up key on the keyboard. The keyboard repeat rate is an operating system value that we can retrieve.

There are actually two values:

private static int _delayRate = 
    System.Windows.SystemParameters.KeyboardDelay;
private static int _repeatSpeed = 
    Math.Max(1, System.Windows.SystemParameters.KeyboardSpeed);

The delay rate is how long we should wait before starting the repetition, and is given in multiples of 250ms. Roughly speaking, humans can determine and control actions with lengths of time of about 200ms, so 250ms is a good value to start with. Any shorter and the repetition might start when it was not intended (say, if they just click the button instead of holding it down).

The keyboard speed is the number of times per second we should repeat—sort of. The value can be 0, so because of the way I use it below I want to sure it’s at least 1.

To allow us to hold the button down, we need to override the default mouse handling of a button which is to disable the standard LeftMouseButtonDown/Up messages. Instead, we need to handle the PreviewMouseLeftButtonDown message and its corresponding Up message.

When we handle the down message, we need to set a timer for the keyboard delay value. When we handle the timer’s tick, we need to increment (or decrement) and change the timer’s interval to the repeat speed. This repeat speed is calculated merely by dividing 1000ms (1s) by the rate per second. There may be better ways, but this gets pretty close to the rate experienced by the keyboard on my computer. Finally, when the mouse button is released we need to stop the timer. We also do a final increment, which will cover the case where the user clicks instead of holds.

We also need to capture the mouse in case the user moves it off the button—otherwise the timer will just keep incrementing forever.

Here’s the code:

 

private DispatcherTimer _timer = 
    new DispatcherTimer();
private static int _delayRate = 
    System.Windows.SystemParameters.KeyboardDelay;
private static int _repeatSpeed = 
    Math.Max(1, System.Windows.SystemParameters.KeyboardSpeed);
 
private bool _isIncrementing = false;
 
public NumericEntryControl()
{
    ...
 
    buttonIncrement.PreviewMouseLeftButtonDown += 
        new MouseButtonEventHandler(
            buttonIncrement_PreviewMouseLeftButtonDown);
    buttonIncrement.PreviewMouseLeftButtonUp += 
        new MouseButtonEventHandler(
            buttonIncrement_PreviewMouseLeftButtonUp);
 
    buttonDecrement.PreviewMouseLeftButtonDown += 
        new MouseButtonEventHandler(
            buttonDecrement_PreviewMouseLeftButtonDown);
    buttonDecrement.PreviewMouseLeftButtonUp += 
        new MouseButtonEventHandler(
            buttonDecrement_PreviewMouseLeftButtonUp);
 
    _timer.Tick += new EventHandler(_timer_Tick);
}
 
void buttonIncrement_PreviewMouseLeftButtonDown(
    object sender, MouseButtonEventArgs e)
{
    buttonIncrement.CaptureMouse();
    _timer.Interval = 
        TimeSpan.FromMilliseconds(_delayRate * 250);
    _timer.Start();
 
    _isIncrementing = true;
}
 
void buttonIncrement_PreviewMouseLeftButtonUp(
    object sender, MouseButtonEventArgs e)
{
    _timer.Stop();
    buttonIncrement.ReleaseMouseCapture();
    IncrementValue();
}
 
void buttonDecrement_PreviewMouseLeftButtonDown(
    object sender, MouseButtonEventArgs e)
{
    buttonDecrement.CaptureMouse();
    _timer.Interval = 
        TimeSpan.FromMilliseconds(_delayRate * 250);
    _timer.Start();
 
    _isIncrementing = false;
}
 
void buttonDecrement_PreviewMouseLeftButtonUp(
    object sender, MouseButtonEventArgs e)
{
    _timer.Stop();
    buttonDecrement.ReleaseMouseCapture();
    DecrementValue();
}
 
void _timer_Tick(object sender, EventArgs e)
{
    if (_isIncrementing)
    {
        IncrementValue();
    }
    else
    {
        DecrementValue();
    }
    _timer.Interval = 
        TimeSpan.FromMilliseconds(1000.0 / _repeatSpeed);
}

And voila! A NumericEntryControl that’s basic and easy-to-use for both keyboard and mouse.

Further improvements

This isn’t the last word in numeric entry controls, by any means. There are many ways to accomplish it, and this is one that worked well for me. There are a number of further enhancements you could do (and perhaps should do):

  • More validation
  • Ensure that MaxValue >= MinValue
  • Set focus to the TextBox when the control gains focus (maybe)
  • Define strokes to increment and decrement with a stylus
  • The user can change the keyboard repeat rate through Control Panel. This program could be modified to listen for updates to this value.

There’s also another, really cool feature that I will add to this in a future post.

Download full source.

Found this article helpful? Want a resource of hundreds of similar, how-to tips? I’ve written a book that covers topics like this and more in C# 4. Check out C# 4.0 How-To!

Popularity: 10% [?]

How to learn WPF (or anything else)

I’ve recently been learning WPF. This is a huge topic that is uncontainable by any single book, tutorial, or web-site. The complexity and breadth of this framework is nearly oppressive, but the results are incredible. Or rather, I should say, potentially incredible.

My first book, C# 4.0 How-To is now shipping! If you like tips you can use, check it out!

From everything I’ve read, people who have suffered through the WPF learning curve have this to say, more or less:

yeah, it was really tough going for a few months. But now I can create awesome apps in a fraction of the time it would take with older technologies.

So with that in mind, I really do want to learn WPF. I have a number of C# references, weighty tomes that bend my shelves, but the main book I use is Programming WPFby Chris Sells and Ian Griffiths. I really like this book—it goes in deep. However, I realized that reading through it cover to cover and doing all the sample apps wasn’t going to work—it gets boring, no matter how good the book is. So here is my recommendation on how to learn WPF (and it probably applies to any programming technology):

  1. Start reading the book, do the code, type stuff in, copy it, tweak it. Do this for as long as you can.
  2. Once step 1 becomes boring, STOP. It is not productive to force yourself through the whole thing like this.
  3. Find a sample project in your target technology. I used Family.Show. There are plenty out there.
  4. Think of a project YOU find interesting that would be good in [WPF|other]. Start doing this. Even if you don’t know where to start at all.
  5. While getting started, every step will be a challenge. Figure it out step-by-step, going back to the book and online resources.

You might be tempted to skip steps 1-2. I think this is a bad idea. You need at least some foundational understanding. Only when you can’t take it any more and you’re in danger of quitting, move on.

This has worked well for me in learning WPF. I decided to implement a game (if it ever gets into a polished state, I’ll share it).

Don’t underestimate the challenges in step 4, though. I had to think about how to even start, going back to the book numerous times, reading large sections. I looked up articles online about patterns and WPF, user controls, and more. Many seemingly-small steps in just displaying windows took hours to figure out. Figuring out data binding (really figuring it out in the context of my app) took hours. The point of doing your own project isn’t because it’s easier than following the book—it’s because it’s fun and you have more motivation to learn.

My first book, C# 4.0 How-To is now shipping! If you like tips you can use, check it out!

Popularity: 16% [?]

NDepend: A short review

NDepend is a tool I’d heard about for years, but had yet to really dive into recently. Thanks to the good folks developing it, I was able to try out a copy and have been analyzing my own projects with it.

Here’s a brief run-down of my initial experience with it.

Installation

There is no installation file—everything is packaged into a zip. After running, I was greeted by a project selection screen, in which I created a new project and added some assemblies. NDepend main screen

Analysis

Once you have all the assemblies you want to analyze selected, you can run the analysis, which generates both an HTML report with graphics, and an interactive report that you can use to drill down into almost any detail of your code. Indeed, it’s almost overwhelming the amount of detail present in this tool.

One graph you see almost immediately is Abstractness Vs. Instability.

Abstractness vs. Instability

This is a good high-level overview of your entire project at the assembly level. Basically, what this means is that assemblies that are too abstract and unstable are potentially useless and should be culled, while assemblies that are concrete and stable can be hard to maintain. Instability is defined in the help docs in terms of coupling (internal and external), while abstractness is the ratio of abstract types to total types in an assembly.

This is followed by the dependency graph:

Dependency graph

After these graphics come lots of reports that dig into your code for all sorts of conditions.

For example, the first one in my report was “Quick summary of methods to refactor".” That seems pretty vague, until you learn how they determine this. All the reports in NDepend are built off of a SQL-like query language called CQL (Code Query Language). The syntax for this is extremely easy. The query and result for this report are:

NDepend_RefactorMethods

With very little work on my part, I instantly have a checklist of items I need to look at to improve code quality and maintainability.

There are tons of other reports: methods that are too complex, methods that are poorly commented, have too many parameters, to many local variables, or classes with too many methods, etc. And of course, you can create your own (which I demonstrate below).

Interactive Visualization

All of these reports are put into the HTML report. But as I said, you can use the interactive visualizer to drill down further into your code.

The first thing you’re likely to see is a group of boxes looking like this:

NDepend_Metrics

These boxes show the relative sizes of your code from the assembly level down to the methods. Holding the mouse over a box will bring up more information about the method. You can also change the metric you’re measuring by—say to cyclomatic complexity.

Another view, perhaps the most useful of all is the CQL Queries view. In this, you can see the results from all of hundreds of code queries, as well as create your own. For instance, I can see all the types with poor cohesion in my codebase:

NDepend_Cohesion

In this view, the CQL queries are selected in the bottom-right, and the results show up on the left. The metrics view highlights the affected methods.

Creating a query

Early in the development of my project, I named quite a few classes starting with a LB prefix. I’ve changed some of them, but I think there are still a few lying around and I want to change them as well. So I’ll create CQL query to return all the types that begin with “LB.”

   1: // <Name>Types beginning with LB</Name>
   2: WARN IF Count > 0 IN SELECT TYPES WHERE 
   3:  NameLike "LB" AND     
   4:  !IsGeneratedByCompiler AND 
   5:  !IsInFrameworkAssembly     

NDepend_LB That’s it! You can see the results to the right. It’s ridiculously easy to create your own queries to examine nearly any aspect of your code. And that’s if the hundreds of included queries don’t do it for you. In many ways, the queries are similar to the analysis FxCop does, but I think CQL seems generally more powerful (while lacking some of the cool things FxCop has).

 

VS and Reflector Add-ins

NDepend has a couple of extras that enable integration of Visual Studio (2005 and 2008) and NDepend and Reflector. When you right-click on an item in VS, you will have some additional options available:

NDepend_VSPlugin1

Clicking on the submenu gives you options to directly run queries in NDepend. Very cool stuff.

Summary and where to get more info

If you are at all interested in code metrics, and how good your code is behaving, how maintainable it is, you need this tool. It’s now going to be a standard part of my toolbox for evaluating the quality of my code and what parts need attention.

If you’re using NDepend for personal and non-commercial reasons, you can download it for free. It doesn’t have all the features, but it has more than enough. Professional use does require a license.

One of the things I was particularly impressed with was the amount of help content available. There are tons of tutorials for every part of the program.

I’m going to keep playing with this and I’m sure I’ll mention some more things as I discover them. For now, NDepend is very cool—it’s actually fun to play with, and it gives you good information for what to work on.

Links:

Popularity: 13% [?]

Better Find In Files results in Visual Studio

Sara Ford has an awesome tip for Visual Studio on how to customize the formatting of search results.

Popularity: 10% [?]

Converting OLE_COLOR to System.Drawing.Color

I’ve been working on a project using Visual Studio Tools for Office 2008 (VSTO) and at one point I needed to get the colors for categories in Outlook 2007. There are actually 3 colors, and they are returned as uint’s–why the .Net wrappers don’t convert to colors for you, I don’t know (to avoid linking to System.Drawing?).

The important thing is to convert them into the friendly System.Drawing.Color objects I know and love. For this task, there exists a handy ColorTranslator class. There is a FromOle method that does the exact chore you need. Here’s a sample of my code:

 

   1: private void GetCategoryColors()
   2: {
   3:     foreach (OutlookLib.Category category in
   4:         Application.ActiveExplorer().Session.Categories)
   5:     {
   6:         CategoryColor color = new CategoryColor(
   7:             ColorTranslator.FromOle((Int32)category.CategoryGradientTopColor),
   8:             ColorTranslator.FromOle((Int32)category.CategoryGradientBottomColor),
   9:             ColorTranslator.FromOle((Int32)category.CategoryBorderColor));
  10:         _categoryCollection[category.Name] = color;
  11:     }
  12: }

Popularity: 10% [?]

Fixing Printing Problems with IE7 and Vista

If you are having problems printing from Internet Explorer 7 under Windows Vista, check to see if you have AVG 8.0 installed. If so, get the latest version from http://free.grisoft.com. I did have build 8.0.101 and upgraded to build 8.0.138–everything works fine now.

I’ve also seen reports that it could be an error while running IE7 in Protected Mode. There’s a thread in the Microsoft forums about this.

Good luck.

Popularity: 7% [?]

log4cxx + VS2005 + Windows SDK v6.0 = compile error

If you are following the instructions to build log4cxx 0.10 in Visual Studio 2005, and you have the Windows Platform SDK v6.0 installed, you may get errors compiling multicast.c in the apr project.

I found the solution, and it’s pretty easy. Open up multicast.c and edit the lines:

136: #if MCAST_JOIN_SOURCE_GROUP

148: #if MCAST_JOIN_SOURCE_GROUP

to be, instead:

136: #if defined(group_source_req)

148: #if defined(group_source_req)

 

e voilà! now it compiles.

Popularity: 8% [?]

Virtual PC 2007 Tips and Tricks

 

This release of Virtual PC 2007 SP1 provides updates to existing features and introduces support for the following:

  • Windows Vista with Service Pack 1 (SP1) Business, Ultimate, and Enterprise operating systems as a host operating system

  • Windows Vista with SP1 Business, Ultimate, and Enterprise as a guest operating system

  • Windows Server 2008 Standard as a guest operating system

  • Windows XP with Service Pack 3 as both a guest and host operating system

  • Read The Virtual PC Guy’s Weblog
  • If you need, say, two virtual machines, one with Windows Vista and one with Windows Vista SP1, install Vista onto a new machine, then copy the machine files and install SP1 on one copy–much faster than installing Vista twice.
  • Need a screen shot of what’s in the virtual machine? Look at the Edit menu and choose “Select All” then “Copy”–a bitmap of the VM window will be on the clipboard. (This is how I got the capture of my BASIC graphics output from a previous post).

Popularity: 7% [?]

Opening Visual Studio solutions from Explorer in Vista

You’ve installed Visual Studio 2005 on Vista and dutifully changed it to run as administrator, like you’re supposed to. And then…

Problem: Visual Studio 2005 solutions no longer open when you double-click them in Windows Vista. In fact, when you double-click nothing happens.

Solution: Change them to open with Visual Studio 2005 directly instead of the vslauncher.exe (which opens up the solution with the correct version of Visual Studio if you have more than one).

Caveat: Only makes sense if  you use only Visual Studio 2005.

How-to:

  1. Right-click on a solution file.
  2. Choose “Open With…”
  3. Choose “Browse…”
  4. Browse to file “C:\Program Files\Microsoft Visual Studio 8\Common7\IDE\devenv.exe” (or wherever you installed Visual Studio)
  5. Click “Open” button
  6. Check “Always use the selected program to open this kind of file”

openwith

Now your solutions will load Visual Studio, bring up the UAC prompt, and it all works great.

Found via here and here.

Popularity: 5% [?]

Software Pick: SyncMyCal

With the acquisition of a Blackberry I wanted to be able to sync both my work and home Outlook setups to the Blackberry (and to each other). I tried a number of free tools (though they aren’t that easy to find) and quickly concluded I would need a better solution.

Enter SyncMyCal. It’s easy, it’s cheap (only $25), and you can try for free. I rarely have duplicated events, and I don’t have to think about it ever–it just WORKS.

How it works: SyncMyCal synchronizes an Outlook calendar with a Google calendar. First I created a Google calendar, then I set up SyncMyCal on both work and home computers. I set the home computer to take priority in conflicts, but at work I set the Google calendar to take priority over Outlook–this way there’s a hierarchy of priority that helps to prevent unresolvable conflicts and duplicates.

I bought it days before Google released their Outlook sync tool, but SyncMyCal can do a lot more and I don’t regret the purchase one bit.

The latest version also syncs contacts, but I haven’t used that yet.

Popularity: 7% [?]