Andrej Tozon's blog

In the Attic

NAVIGATION - SEARCH

How well do you know your Culture?

When doing code reviews, I often stumble upon a piece of code with some culture-specific information hard-coded in it. One example of this being month names:

string[] months =
   
{
        "January",
       
"February",
        "March",
        "April",
        "May",
        "June",
        "July",
        "August",
        "September",
       
"October",
        "November",
        "December"
   
};

This is all fine if your application is intended for English spoken users and all that, but hey - why try and duplicate something, what's already been done for you? CultureInfo class has all the information you need:

string[] months = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;

And if you need the name of the months in some other supported language, all you have to do is ask [this one's for Slovenia):

string[] months = CultureInfo.GetCultureInfo("sl-SI").DateTimeFormat.MonthNames;

Then again, if all you need is month names in shortened form, the class can also help:

string[] months = CultureInfo.CurrentCulture.DateTimeFormat.AbbreviatedMonthNames;

If you're after just one specific month name, it will bi provided for you [the following line will get you February - obviously]:

string month = CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(2);

And so on... The same pattern applies for day names, etc. If there is anything specific that you would want to know about a certain culture, CultureInfo class will give you all the information you need. Given these possibilities, one can even create a custom culture using the CultureAndRegionInfoBuilder class. There's quite a few examples of where this would come in useful.

One thing to note though: The MonthNames properties described above will return you the string array of 13 items; although majority of cultures have 12 months in a year, a few apparently have 13, so be aware of that when using these properties. If month names list is intended for a data source that can be bound to, you may want to return the actual number of months. The following method will return the actual number of months in a given year:

int mothCount = CultureInfo.CurrentCulture.DateTimeFormat.Calendar.GetMonthsInYear(DateTime.Today.Year);

The other way would be just skipping the empty months. There are again, several ways to do this - today, the weapon of choice is fashionable - Linq [or rather - its extensions], although it's most likely not the fastest way of doing it:

string[] cultureMonths = CultureInfo.CurrentCulture.DateTimeFormat.MonthNames;
string[] months = cultureMonths.TakeWhile<string>(month => month.Length > 0).ToArray<string>();

The TakeWhile method will return only those items, for which lambda expression would return true. Also not that I could as easy replace the ToArray<string>() method at the end with ToList<string>() and return a generic list of strings:

List<string> months = cultureMonths.TakeWhile<string>(month => month.Length > 0).ToList<string>();

... but since this is most likely a read-only list, it doesn't really matter.

WLM tip: just paste the image to send it over

While conversing over Windows Live Messenger the other day, I became aware that not everybody knows about its feature to send an image over by simply pasting it into the message window. You know, instead of the lengthy process of pasting PrintScreen-ed image into Word or Paint, saving it into a file, then dragging the file into the message window, you can as well copy the image (PrintScreen or Windows Vista's Snipping tool) and paste it directly into WLM's message window. WLM will then automatically create a temporary file and send that over to the receiver...

There, a very quick and simple WLM tip :)

Make your application speak

.NET Framework 2.0 simplified the way of playing audio files from desktop applications. .NET Framework 3.0 takes this one step further by introducing the speech API, residing in the System.Speech namespace (it's basically a wrapper around Microsoft SAPI and is packed in System.Speech.Dll).

Using the SpeechSynthesizer class you can make your computer actually speak the text you feed to it:

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.Speak("Hello world!");

If you don't want to stop your application from blocking the execution while speaking, this is there's the asynchronous equivalent to this method:

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SpeakAsync("Hello universe!");

The class provides a lot of ways of influencing the sound, like changing the rate, volume, providing hints on pronunciation, including existing sounds and changing the voice. Windows Vista comes with the preinstalled voice called Microsoft Anna, while Microsoft Sam should be available on Windows XP.

OK, so I thought I would update my You've got mail application sample by including some spoken text when new mail "arrives". This is the code I used:

PromptBuilder builder = new PromptBuilder();
builder.AppendAudio(new Uri(@"file://\windows\media\windows notify.wav"));
builder.AppendBreak(PromptBreak.Small);
builder.AppendText("You've got mail.");
builder.AppendBreak(PromptBreak.Small);
builder.AppendText("I think it's from your... wife.");

SpeechSynthesizer synth = new SpeechSynthesizer();
synth.SpeakAsync(builder);

And this is the extended You've got mail sample project for download.

Enjoy. A couple of notes though: The speech API does not require you to build a WPF to use it. You can also use it from Windows Forms or a Console application, just as long as you're targeting .NET FX 3.0. And don't forget to reference the System.Speech.Dll.

You've got mail

Paste as Xaml Visual Studio Add-In

Common Windows Presentation Foundation controls don't necessarily provide an intuitive path for upgrading from their Windows Forms equivalents. Take, for example, the RichTextBox control - there is no Rtf property for setting and getting RTF formatted text in WPF's RichTextBox. You can however, still load the RTF text into RichTextBox, using this method (loading RTF text from an embedded resource called MyRtfText):

ASCIIEncoding encoding = new ASCIIEncoding();
byte[] bytes = encoding.GetBytes(Properties.Resources.MyRtfText);

using (MemoryStream s = new MemoryStream(bytes))
{
   
TextRange range = new TextRange(rtfBox.Document.ContentStart, rtfBox.Document.ContentEnd);
   
range.Load(s, DataFormats.Rtf);
}

But how about creating a couple of text lines that would fit right into WPF's RichTextBox? RichTextBox exposes the Document property, which would accept a FlowDocument - and that's a native WPF content element, persisted in Xaml format. If you need to insert a piece of document into RichTextBox at design time, you'll have to know some Xaml to to it. Having to convert some existing text from RTF or other rich text format (pasting from Word seems like a good idea) requires a converter...

Luckily, such a converter is already built in WPF - it's the RichTextBox itself! The following snippet will stuff the text from the clipboard (text format doesn't matter, as long it's text) into the RichTextBox and get it out as a FlowDocument:

RichTextBox box = new RichTextBox();
box.Paste();

string text;
TextRange range = new TextRange(box.Document.ContentStart, box.Document.ContentEnd);

using (MemoryStream stream = new MemoryStream())
{
   
range.Save(TextDataFormat.Xaml.ToString());
   
stream.Seek(0, SeekOrigin.Begin);
   
using (StreamReader reader = new StreamReader(stream))
   
{
        text = reader.ReadToEnd();
   
}
}

And this is the core of this very simple Visual Studio 2008 Add-In that I've created - it will allow you to paste any text from the clipboard into Visual Studio as XAML.

Installing the Add-In is as easy as copying a DLL, included in the zip file [see link below], into *\My Documents\Visual Studio 2008\Addins folder and (re)start Visual Studio 2008. You'll find the new command under Tools menu.

image 

Download the Add-In. Full Add-In source code will follow...

On a side note... WPF future looks bright: performance and VS Designer improvements, new setup framework, new controls (DataGrid, Ribbon, Calendar, ...) See this ScottGu's post for more details.

Express your love with Silverlight :)

Want to impress your loved one with a Valentine's card tomorrow? Why not sending her/him a Silverlight Valentines? Silverlight and Windows Live teams created this card template for you to modify it and share your love. The process only takes four steps - you can pick a photo from either Windows Live Spaces or Flickr, enter a short text or poem, choose accompanying music and send the card.

image

A cool example of integrating other services with Silverlight... Just the right one to end up on CodePlex or MSDN Code Gallery someday ;)

Rethinking a mobile

With HTC out of the picture and iPhone on hold, there's a new mobile making a great entrance - Sony Ericsson just announced XPERIA™ X1! Windows Mobile (! a new direction for SE !), QUERTY keyboard + finger touch navigation on 800x480 display, 3.2MP camera and lots of connectivity options are just a few features, which make this phone jump way up high in the candidate list. The only question is - again - availability... "Available in “selected markets” from the second half of 2008"? Huh!

You've got mail: Windows Forms &amp; WPF interop

One of my favorite samples when talking about WPF is showing a rotating 3D letter 'e' in a Windows Forms application. You know, something like those "you've got mail" computer messages, seen in many Hollywood movies. Windows Forms/WPF interoperability features make this kind of stunt very easy to pull off and this is the recipe to make in happen in 15 minutes...

First, you'll have to come up with some kind of 3D element, which you can import in WPF. I used electric rain's ZAM 3D tool, which has the ability to export 3D elements directly to XAML, which can be later picked up and additionally arranged with  Expression Blend, for example. It actually took me just a couple of minutes to create a 3D letter 'e' and import the scene into Blend.

blendmail1

Rotating the 3D element was done by animating ViewPort's camera by setting 5 progressive key frames of its Rotate Transform property.

image

We need to make the element reusable, so we'll transform it to a user control. Expression Blend 2 (currently still in CTP version) fortunately makes this task very easy by exposing the "Make Control" task (Tools | Make Control...)

OK, half done... We now have a user control with rotating 3D element and a WPF Window, simply displaying it.

The next step is adding a new Windows Form to the project. Save the project in Blend, switch over to Visual Studio (2008) and add a new Form. Visual Studio will make sure all necessary interop assemblies will be added to the project in this process.

With newly created form displayed in the designer area and open a Toolbox. Right at the top (or elsewhere, depending on your project's name), there should be your WPF user control, ready to drag onto the form. When doing so, Visual Studio will create your control, hosted in the ElementHost control (a Windows Forms control, which can host a WPF element). Set control's size to a desired value and you're done.

image

Download the sample project here.

Undeleting shift-deleted emails in Outlook

This one's for future reference...

It so happened that I accidentally "permanently" deleted some emails from Outlook... You know, a well-trained keyboard sequence routine - select some (spam) email, shift+delete, enter, and spam's gone. It turned out I happened to select all email in my Outlook and when I managed to stop the deleting, the last two months of email were gone.

This could easily be a tragedy, if I weren't keeping my email accounts with gmail/google apps. However, I do like keeping copies of my email on my desktop, so I wanted to get that two months of lost email back.

I knew that shift-deleting items in Outlook's list doesn't really remove the email's content from the data file [at least until the next Compact command], I just wasn't sure how to get it back. Googling for solution returned many (payable) products and services, assuring positive results, but somewhere down the road, I managed to land on Blake Handler's page, giving a simple solution. Apparently the utility, called Inbox Repair Tool, used for diagnosing and repairing corrupted Outlook's Personal Folders files (.pst), also resets the deleted flag in the repair process. You just have to find a way to corrupt the .pst file. Here's the quick rundown:

  1. Backup your Outlook.pst file [Inbox Repair Tool will do this for you as well]
  2. Edit Outlook.pst in some HEX editor
  3. Alter one or couple of bytes in the file (I changed the first byte and that worked for me)
  4. Run Inbox Repair Tool [ScanPST.exe, if using Office 2007, it's in [c:\]\Program Files\Microsoft Office\Office12\
  5. Start Outlook. Undeleted email should be back.