Here we are on the 10th installment of what I thought would be a pretty simple walk-through into writing standard, distributable applications using WPF. This walk-through started out mirroring the old Scribble tutorial (http://msdn2.microsoft.com/en-us/library/aa314520(VS.60).aspx) but has recently turned into me complaining about things I don't understand very well. Specifically, I'm just not getting my head around the localization story with WPF and how it interacts with the built-in ApplicationCommands.X classes and keyboard access (mnemonics in MFC). So, rather than complaining, let's just solve the problem.
The problem is this: ApplicationCommands.X classes give the developer a nice, automatically localized hook to use in hooking up UI elements to business logic to be executed. These commands are automatically localized based on the currently selected UI culture. These commands don't have access keys for use in MenuItem UI elements, so if I use the ApplicationCommands.New command in the file menu, I can't invoke it via Alt+f,s (something I've been doing from the old DOS days and am not interested in changing).
Solution 1 -- Implementing our own ScribbleCommands class from scratch
Here's a possible example. We could just implement our own ApplicationCommands-like class to serve up all of the commands we're interested in using from the UI. After all, we already implemented ScribbleCommands.Exit, so we can do something like that for the rest of the commands. This has the downside of requiring us to localize all of the text ourselves.
Solution 2 -- Implementing our own ScribbleCommands class as an adapter around ApplicationCommands
This is the one we're going to pursue. Since we already have ScribbleCommands and since MS already gives us much of the plumbing for the built-in commands classes, we'll just enhance that built-in functionality to convince it to do what we want. Here's the idea: for commands that don't have built-in ApplicationCommands.X implementation, we create string resources for all UI related aspects of the command (Name, Text, Gextures, Gesture display text, Tooltip, and Description). For commands that do have a built-in ApplicationCommands.X implementation, we create string resources for the bits of UI related aspects we want to override (mnemonic character, Tooltip, and Description).
The Scribble.Exit command looks like this:
public static RoutedUICommand Exit { get { return EnsureCommand( Properties.Resources.ExitName, Properties.Resources.ExitText, Properties.Resources.ExitGestures, Properties.Resources.ExitGesturesDisplayText); } } public static string ExitTooltip { get { return Properties.Resources.ExitTooltip; } } public static string ExitDescription { get { return Properties.Resources.ExitDescription; } }
The Scribble.New command looks like this:
public static RoutedUICommand New { get { RoutedUICommand command = ApplicationCommands.New; string commandText = command.Text; int accessIndex = commandText.IndexOf(Properties.Resources.NewAccessKey); if ((accessIndex >= 0) && (commandText.IndexOf('_') < 0)) { command.Text = commandText.Insert(accessIndex, "_"); } return command; } } public static string NewTooltip { get { return Properties.Resources.NewTooltip; } } public static string NewDescription { get { return Properties.Resources.NewDescription; } }
Notice, we have to use our own Tooltip and Description properties here since the built-in commands don't have these items provided. Also, notice we are searching the returned command.Text for a pre-existing _ character. This is so we don't forcibly overwrite any mnemonic that may already be set. Of course, you could just remove it instead.
Using any of these commands in the UI looks exactly the same as before
<MenuItem Command="{x:Static scribble:ScribbleCommands.New}" />
There it is. The code (in Spanish and English) is available at http://www.cavinconsulting.com/Code/Scribble10.zip. To run it in Spanish, just un-comment the marked lines in App.xaml.cs. If you're running Windows XP, be sure to install the Spanish language pack for the .NET 3.0 Framework (http://www.microsoft.com/downloads/details.aspx?FamilyID=41c61d2a-d411-4dde-9013-bb08eb688bb6&DisplayLang=en). Unfortunately, if you're running Vista, it isn't as simple as just installing the language pack. If you have Ultimate or Enterprise edition, you should see the language packs on Utimate Updates. I didn't, however, and ended up downloading it directly from here.
I'm still not sure what I think about this approach. It does salvage the automatic localization provided by the runtime. It allows each language to define their own mnemonics or to fall back on the default mnemonic (if the latter exists in the command). However, on windows Vista, the localization only appears supported on Ultimate or Enterprise editions, and the installation of the appropriate MUI packs doesn't seem as simple as the old language pack model. Also, it limits my target audience to only those fortunate enough to be running an expensive version of Windows.
Disclaimer The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.