Scott Hanselman

I like cake! - Cakemail, Ninjas on Fire, and other Anecdotes

August 6, '08 Comments [81] Posted in Musings
Sponsored By

When I worked with Travis Illig (who is the origin of the term "Hanselminute," by the way) and Stuart Thompson at Corillian/CheckFree, we had a project manager who didn't totally "get" stuff.

What I mean is that we'd be in a meeting, perhaps a feature meeting or something, and we'd be firing on all cylinders. Everyone was working well together, communicating clearly, finishing each other's sentences, just an all around great day. Designs become clear, backlog items were created at a furious pace, and it was generally felt that everyone in the meeting "grokked" what we needed to do.

At this point this particular project manager, who had been quiet until this point, would ask something like

"Now, wait, are you saying that Java replaces XML?"

...and silence. Crickets. We were hearing English *words*, but not a cohesive sentence. After all that, the last hour of banging through stuff, he had not just a disconnect, but a total fundamental misunderstanding of some aspect of computers and systems design.

I don't remember who originally said it, it might have been me or Travis, but at some point after one of these uncomfortable moments, someone broke the silence with the non sequitur:

"I LIKE CAKE!"

...and the room exploded. From that point on, any time anyone in any meeting said something that was far enough off topic or sufficiently non-sequiturial, someone would declare "I LIKE CAKE!"

All off-topic email responses are now declared "Cakemail" as in, "Man, I got some Cakemail from Fred this morning. Made no sense." I still use this to this day and it still makes me smile.


Jesse asked me how I was doing yesterday and I replied "Ninjas on fire, man." Four years ago when Halo 2 was coming out it was described like this.

"Halo 2 is alot like Halo 1, except it's Halo 1 on fire going 120 miles per hour through a hospital zone chased by helicopters and ninjas. And the ninjas are all on fire too." -Jason Jones

For me and some of my compatriots, it also become a phrase that referred to our current workload, like:

"How's work?"

"I'm being chased by ninjas."

"Are they on fire?"

"Not yet."

"Oh, so it's Tuesday. You wait."

The short-hand just became "ninjas on fire, man" as a response to when you're totally overwhelmed with deadlines and work.


Open Thread: What anecdotes about life in Software Development do you have to share, Dear Reader? What short-hands or code-words have you developed?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

The Weekly Source Code 31- Single Instance WinForms and Microsoft.VisualBasic.dll

August 2, '08 Comments [19] Posted in Learning .NET | Source Code | VB | Windows Client
Sponsored By

I got an interesting question recently emphasis mine:

I am regular reader of you blog. I need some help in single instance winform. I have to open application when a file (.ext) is clicked (File is associated with that application like .doc with WINWORD). Application should be single instance. When I click the .ext file it should open the application with that content. If an instance is runnng it should ask the user whether you want to close this application and then open the new .ext file. Need help in C#.

Some questions are more interesting than others, but I think we've all had to solve this "Single Instance" problem over and over again over the last 15 years. I did this with a Dan Appleman VBX in Visual Basic 3 and I've seen piles of solutions with Mutexes and all sorts of overly complex dancing to solve this apparently simple problem. This is a really old technique, but three years later, there's just not enough people that know that the WindowsFormsApplicationBase class exists and has a lot of useful functionality in it.

There was an interesting thread over here about handling this. Someone asked the question and someone said "WinForms 2.0 has support for single instance apps built in." and the next guy said "Only for Visual Basic applications, though."

Microsoft.VisualBasic.dll has got to be one of the most useful standard installed parts of the .NET Framework out there. Folks are afraid to reference it from C#. It feels wrong.

Kind of like busting out with French words in the middle of English sentences, referencing Microsoft.VisualBasic.dll has that je ne sais quoi that tends to give C# folks a feeling of mal de mer but that assembly has a specific raison d'ĂȘtre. See? Feels wrong, but it still works. There's good stuff in Microsoft.VisualBasic.dll, and just because it isn't System.Something doesn't mean you shouldn't reference it with abandon. Go nuts.

Back to the problem. There's many examples, but the easiest one I've seen was over at OpenWinForms.com and it was written in C# referencing Microsoft.VisualBasic.dll. I've modified it here to make a single instance app that will open a text file name passed in on the command line. If you call the same application a second time, it'll take the new command line argument and load that text file in the first instance.

Launching it as "SuperSingleInstance foo.txt" from a command line...

Single Instance

Then, from the same command line, while the first one runs, launching a second "SuperSingleInstance bar.txt" from a command line. The first instance is reused, brought to the front, and gets an event letting us know someone tried to launch us and that event includes the new command line.

Single Instance (2)

The code is really cool as all the work is in WindowsFormsApplicationBase. It's a little confusing because you have to call a controller instance and tell it about your MainForm, rather than calling Application.Run(). The StartupNextInstance event is called in your first application when a second instance of your app gets fired up. It talks cross process between the new second instance and your original one and passes over the command line.

using System;
using System.Windows.Forms;
using Microsoft.VisualBasic.ApplicationServices;

namespace SuperSingleInstance
{
static class Program
{
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
string[] args = Environment.GetCommandLineArgs();
SingleInstanceController controller = new SingleInstanceController();
controller.Run(args);
}
}

public class SingleInstanceController : WindowsFormsApplicationBase
{
public SingleInstanceController()
{
IsSingleInstance = true;

StartupNextInstance += this_StartupNextInstance;
}

void this_StartupNextInstance(object sender, StartupNextInstanceEventArgs e)
{
Form1 form = MainForm as Form1; //My derived form type
form.LoadFile(e.CommandLine[1]);
}

protected override void OnCreateMainForm()
{
MainForm = new Form1();
}
}
}

The Form is trivial, just loading the text from the file into a TextBox.

using System;
using System.Windows.Forms;
using System.IO;

namespace SuperSingleInstance
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
string[] args = Environment.GetCommandLineArgs();
LoadFile(args[1]);
}
public void LoadFile(string file)
{
textBox1.Text = File.ReadAllText(file);
}
}
}

There's other nice functionality in WindowsFormsApplicationBase like support for SplashScreens and network availability events. Again, check out the good stuff over at http://www.openwinforms.com/, like the Controller I used in this post.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Logitech Harmony One Remote Control Review

August 2, '08 Comments [26] Posted in Reviews
Sponsored By

lmn A little over three years ago I finally solved my Universal Remote control problems with a Logitech Harmony 880. To this day, I still recommend it all the time. It's a great balance of functionality and a good price (as low as US$129).

"Why is the TV full? WHO is watching America's Next Top Model?"

However, the one Achille's Heel of the 880 was it's battery life (it gets weird memory) and the battery contacts. Sometimes it just doesn't touch the contacts in its cradle right, and I'll wake up the next day with a dead battery and a confused wife.

"So, the TV goes on Input 3 but the Receiver is on Input 7? But what controls the volume? Why is the TV muted?"

Universal Remotes are all about the WAF (Wife Acceptance Factor) or SAF (Spouse Acceptance Factor). Whatever hell you've got yourself into in the setting up of your TV and "Media Area," you need to dig yourself out with a decent remote.

"How do I turn this thing on? YOU set it up! It says 'PC Load Letter'?"

HarmonyOneMy 880 solved these problems and was the only remote The Wife didn't despise. She was starting to get a little torqued with the battery life, so (gadget-using adsense-spender that I am) I've just replaced it this evening with the Logitech Harmony One.

"Screw this, I'm using the TV in the spare room!"

I love the 880. It had a few problems, that I detailed in my review, but for the most part it was bangin'.  The software then was 4.3 and now it's on 7.4.3 and it runs in Vista x64, so you gotta give Logitech credit for not shutting me out based on my OS of choice.

"Where is the remote?"

My first concern was "How am I going to move my settings over?" I had this thing TRICKED out. It works. You configure the Logitech Remotes using a Wizard over USB. The remote shows up as a "Human Interface Device" to Vista, and I didn't have to install drivers for the new one.  It just used a generic driver, which was comforting. Works on Win2k, XP, Vista, and OS X.

"Seriously, did you open the remote with a screwdriver?"

As soon as I logged into the software with my original remote's online login I noticed a button that said "Upgrade Remote." Sweet. It gave me the choice to keep this login and move my old settings to the new remote, minus some custom buttons I had done, OR start from scratch with a new login. I upgraded and the remote just worked. Everything as I had it, with brighter screen and upgraded graphics.

"I just want to watch TV. Come on!"

The software that you use to configure the device from your desktop is Activity-based, which makes non-technical spouses happy. You click "Watch TV" and "Play Xbox" and the remote figures it out. Here's the most important thing to grok about this remote. It does NOT use macros or record series of button presses. It's a smart state machine and knows what state each device is in and what codes to change states. This basic fact makes this remote SO much easier than the dance of IR codes I've programmed in the past.

"Where is the 'Denzel' button?"

You should be sure to use the "discrete" commands, meaning a separate IR code for ON and OFF rather than a Toggle, when possible. That way there's less state that can get out of whack. I was not able to do that complete because the Sharp Aquos doesn't have Discreet IR codes for the Input Menu, but if you get out of sync (perhaps someone walks in front of the remote while it's working) you just click HELP and it walks you through a wizard to get its state back. "Is the TV on? Is the Xbox on? etc..."

image

There's a great site for Harmony Icons at http://www.iconharmony.com/. It includes hundreds of networks and channels, including many, many international channels so you're not left out if you're not in the US. I setup all the favorites on 4 pages:

image

Harmony Remotes ComparedIt's really incredibly simple to get the remote setup the way you want it. It'll handle 15 devices (I have 4) although your activities my not be device related. They might be "Listen to Radio" or "Watch CD." They can be configurable to you can create your own "Listen to XM Radio" or "Launch Media Center" if you like.

"How much did that thing cost? Don't even tell me."

Why did I upgrade? There's a number of new features in this remote, other than the fact that it's been completely redesigned.

  • Way better battery contacts. It's tight and unambiguous when it's on the charger.
  • Completely new ergonomics. It feels a lot better.
  • New button lay out. Buttons make more sense, they are organized in zones. Just look at the side-by-side. The 880 LOOKED cool but FELT weird. Can you find the volume controls on the remote on the right?
  • Touch screen. Everyone tried to press the pictures on the 880, but it's not a touch screen! Instead, you press the tiny side buttons next to the picture. Meh. The Harmony One is touch screen for the big stuff.

I'm thrilled with the new remote.

"What have you done?! Where did this remote come from. Where's the other one? You keep changing stuff!"

The wife is happy too. I can tell.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Hanselminutes Podcast 124 - Tim Bray on Microblogging and Widefinder

August 1, '08 Comments [2] Posted in Podcast
Sponsored By

Tim My one-hundred-and-twenty-fourth podcast is up. This interview was setup on Twitter. Tim Bray is a Distinguished Engineer at Sun. He co-edited the XML and XML namespace specs back in the day as well as working on Atom. He is on Twitter at http://twitter.com/timbray. Tim has been running the Wide Finder 2 Project that you can learn more about at the Wide Finder Project Wiki. It is an attempt to answer this interesting question: "What is a good way to write computer programs to take advantage of modern slow-clock-rate/many-core computers, without imposing excessive complexity on programmers?"

Subscribe: Subscribe to Hanselminutes Subscribe to my Podcast in iTunes

If you have trouble downloading, or your download is slow, do try the torrent with µtorrent or another BitTorrent Downloader.

Do also remember the complete archives are always up and they have PDF Transcripts, a little known feature that show up a few weeks after each show.

Telerik is our sponsor for this show.

Telerik's new stuff is pretty sweet, check out the ONLINE DEMO of their new ASP.NET AJAX suite. RadGrid handles sorting, filtering, and paging of hundreds of thousands of records in milliseconds, and the RadEditor loads up to 4 times faster and the navigation controls now support binding to web services on the client.

As I've said before this show comes to you with the audio expertise and stewardship of Carl Franklin. The name comes from Travis Illig, but the goal of the show is simple. Avoid wasting the listener's time. (and make the commute less boring)

Enjoy. Who knows what'll happen in the next show?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Learning WPF with BabySmash - Manually Managing ClickOnce and some more Designer Goodness

August 1, '08 Comments [22] Posted in BabySmash | Windows Client | WPF
Sponsored By

NOTE: If you haven't read the first post in this series, I would encourage you do to that first, or check out the BabySmash category. Also check out http://windowsclient.net/ for more developer info on WPF.

BACKGROUND: This is one of a series of posts on learning WPF. I wrote an application for my 2 year old using WPF, but as I'm a Win32-minded programmer, my working app is full of Win32-isms. It's not a good example of a WPF application even though it uses the technology. I'm calling on community (that's you, Dear Reader) to blog about your solutions to different (horrible) selections of my code. You can get the code http://www.codeplex.com/babysmash. Post your solutions on your blog, in the comments, or in the Feedback and we'll all learn WPF together. Pick a single line, a section, or subsystem or the whole app!

One of the pieces of feedback on BabySmash! was that even though people like that the application automatically updates (via ClickOnce) when they sit down to play BabySmash! their babies want to play it NOW. They didn't like that it tries to update itself when you launch it.

When you setup a ClickOnce application, you get a few choices. You can have the application check for updates before it starts and applying updates before it starts, or you can have it check after it starts and install the updates the next time it starts up. Or, you can say Don't Check For Updates.

I personally find this dialog a little confusing. What this really means is "I'll check manually in code."

Application Updates

At this point, I'm still deploying my app as a ClickOnce app, but now the actual updating is up to me. I used to pop up the Options dialog every time the app started, but again, folks complained, so I had to figure out a way to let them know that an update is available without "stopping the action."

When the app starts up now, it fires of a call to CheckForUpdateAsync from inside System.Deployment.Application and listens for a response. This happens in the background (hence "async"):

if (ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment;
deployment.CheckForUpdateCompleted += deployment_CheckForUpdateCompleted;
try
{
deployment.CheckForUpdateAsync();
}
catch (InvalidOperationException e)
{
Debug.WriteLine(e.ToString());
}
}

If there is an update, I show a label in each MainWindow:

void deployment_CheckForUpdateCompleted(object sender, CheckForUpdateCompletedEventArgs e)
{
ClickOnceUpdateAvailable = e.UpdateAvailable;
if (ClickOnceUpdateAvailable)
{
foreach (MainWindow m in this.windows)
{
m.UpdateAvailableLabel.Visibility = Visibility.Visible;
}
}
}

The label is really simple, just a label with a glow:

<TextBlock x:Name="UpdateAvailableLabel" Visibility="Collapsed" Margin="15,0,0,0" FontSize="12">
<TextBlock.BitmapEffect>
<BitmapEffectGroup>
<OuterGlowBitmapEffect x:Name="UpdateGlow" GlowColor="Red" GlowSize="3"/>
</BitmapEffectGroup>
</TextBlock.BitmapEffect>
<Bold>Update Available - Visit Options to Update BabySmash!</Bold>
</TextBlock>

Except the glow "pulses" between three colors and repeats forever. I set the DesiredFrameRate to a low number like 10 fps rather than what WPF will attempt, which is 60 fps! I'll post later how we can detect how awesome the user's hardware is and scale or turn off animations and effects.

<Window.Resources>
<Storyboard x:Key="Timeline1" Timeline.DesiredFrameRate="10">
<ColorAnimationUsingKeyFrames BeginTime="00:00:00" RepeatBehavior="Forever"
AutoReverse="True" Storyboard.TargetName="UpdateGlow"
Storyboard.TargetProperty="GlowColor" >
<SplineColorKeyFrame Value="#FFCDCDCD" KeyTime="00:00:00"/>
<SplineColorKeyFrame Value="#FFB92121" KeyTime="00:00:01"/>
<SplineColorKeyFrame Value="#FF2921B9" KeyTime="00:00:02"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>

<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Timeline1}"/>
</EventTrigger>
<EventTrigger RoutedEvent="FrameworkElement.Loaded"/>
</Window.Triggers>

Now I've got a nice passive FYI that there's an update.

image

I want to show an update button when the user visits the Options Dialog, which brings me to my awesome volunteer designer Felix Corke (blog). If you want a great WPF or XAML designer, give Felix money. Here's my original Option Dialog:

OldBabySmashOptions

And here's the Felix version:

image

Seriously. It hurts. Brings a tear to my eye.

When the user needs to update, I'll do two things. First, there will be a button that says UPDATE!

updatingoptions

Second, after they've hit Update there will be a Progress Bar and that will update as the new version is download in the background.

 optionsdialogupdating

The API is surprisingly easy to use. We check to see if we were launched from the Network, then I check again (really not needed since I did it earlier, but I like to double-check) for an update. This isn't asynchronous, but it's fast.

I setup two event handlers to listen to the UpdateProgress changing, and to get notification when the system has completed the download of the update. Then I fire off an asynchronous update. 

private void updateButton_Click(object sender, RoutedEventArgs e)
{
if (ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment deployment = ApplicationDeployment.CurrentDeployment;
if (deployment.CheckForUpdate())
{
MessageBoxResult res = MessageBox.Show("A new version of the application is available,
do you want to update? This will likely take a few minutes...",
"BabySmash Updater", MessageBoxButton.YesNo);
if (res == MessageBoxResult.Yes)
{
try
{
deployment.UpdateProgressChanged += deployment_UpdateProgressChanged;
deployment.UpdateCompleted += deployment_UpdateCompleted;
deployment.UpdateAsync();
}
catch (Exception)
{
MessageBox.Show("Sorry, but an error has occurred while updating.
Please try again or contact us a http://feedback.babysmash.com. We're still learning!",
"BabySmash Updater", MessageBoxButton.OK);
}
}
}
else
{
MessageBox.Show("No updates available.", "BabySmash Updater");
}
}
else
{
MessageBox.Show("Updates not allowed unless you are launched through ClickOnce from http://www.babysmash.com!");
}
}

The ProgressChanged event is really convenient because it includes the percentage complete! One less thing for me to do.

void deployment_UpdateProgressChanged(object sender, DeploymentProgressChangedEventArgs e)
{
this.updateProgress.Value = e.ProgressPercentage;
}

The Completed event is also fairly tidy (this one is simplified, and you could always use extra error handling. Note that since this was an asynchronous call, any exceptions that might have occurred elsewhere will show up here in the Error property of the AsyncCompletedEventArgs parameter.

void deployment_UpdateCompleted(object sender, System.ComponentModel.AsyncCompletedEventArgs e)
{
MessageBoxResult res2 = MessageBoxResult.None;
if (e.Error == null)
{
res2 = MessageBox.Show("Update complete, do you want to restart the application to apply the update?",
"Application Updater", MessageBoxButton.YesNo);
}
else
{
MessageBox.Show("Sorry, but an error has occured while updating. Please try again or contact us a http://feedback.babysmash.com. We're still learning!",
"Application Updater", MessageBoxButton.OK);
}
if (res2 == MessageBoxResult.Yes)
{
System.Windows.Forms.Application.Restart();
}
}

I'll update this app to .NET 3.5 SP1 when it ships and I'll get a bunch of new features to make BabySmash! better like:

All in all, not much code for me to switch from an automatic ClickOnce Deployment that I had no control over to one I now have not only complete control over, but also one that fits in more nicely with our always improving UI. Also, an FYI, ClickOnce works with WinForms or WPF equally.

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by SherWeb

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.