The Lottery-Console-Application used at the last WPF-Event @ Microsoft Usergroup Switzerland

August 25th, 2008

Last week we had a great WPF-afterwork-event at Microsoft Usergroup Switzerland (MSUGS) sponsored by Trivadis. I gave a deep-dive session about developing custom controls using WPF with many of it’s features like Dependency Properties, Commands, Routed Events, PART-Elements, Theme-Styles and so on.

At the end of the session a copy of my German WPF-book was drawn. We made a small lottery, but not a normal one. As all attendees were .NET-developers, everyone trusted in .NETs Random-class, so why don’t do it just in code?! We’ve written life a small console-application that did the job for us. As some people asked for the code (of course only the loosers and not the winner of the book ;-) ), here it is:

static void Main(string[] args)
{
  Console.WriteLine();
  Console.WriteLine("  — MSUGS- WPF-Book Lottery");
  Console.WriteLine("  Enter names and a dot (\".\")"
                  + " when names are complete");
  Console.WriteLine();

  List<string> names = new List<string>();
  Console.Write(">");
  string name = Console.ReadLine().Trim();

  while (!name.Equals("."))
  {
    names.Add(name);
    Console.Write(">");
    name = Console.ReadLine().Trim();
  }

  Random random = new Random();
  int winnerIndex = random.Next(names.Count);

  string winner = names[winnerIndex];

  Console.WriteLine();
  Console.WriteLine("Starting lottery…");

  Thread.Sleep(3000);

  Console.Write("And the winner is");

  for (int i = 0; i < 10; i++)
  {
    Thread.Sleep(1000);
    Console.Write(".");
  }
  Console.WriteLine();
  Console.WriteLine();

  Console.WriteLine(winner);

  Console.ReadLine();
}

The Console-Application looks like this:

image

The lucky winner at the MSUGS-event was Stefan, he was at index zero in the names-Collection. Congratulations!

st_msugs_080820

Thanks to MSUGS for the great organization and to all developers who attended in the session. I hope you enjoyed it.

Developing Multicolumn-DropDown/DropDownList with ASP.NET, the GridView and the AJAX Control Toolkit

July 31st, 2008

During the last months I was developing an ASP.NET application and I needed a dropdownlist to display multiple columns in each item. Everyone with a little knowledge in Web-development knows, that HTML doesn’t contain built-in support for multicolumn-DropDowns. HTML only knows a <select>-Tag that can contain multiple <option>-Tags, but each <option>-Tag just represents one column in the dropdown.

In this post we’ll take a look at different possiblities to display the properties of a simple Friend-class in one dropdown-"option". The Friend-Class looks like this:

public class Friend
{
  public Guid ID { get; set; }
  public string FirstName { get; set; }
  public string LastName { get; set; }
  public DateTime BirthDay { get; set; }
}

Below you see the four approaches we’ll look at in this post:

  • The easieast way to do it: Using string concatenation
  • Use third-party controls that have the multicolumn-feature
  • Develop your one multicolumn-DropDown with AJAX Control Extenders
  • Make the multicolumn-DropDown usable for many rows

The easiest way to do it: Using string concatenation

The easiest way I can think of is to use simple string concatenation and a monospace font like courier new. First thing to do is to add an asp:DropDownList to your page. Don’t forget to set it to a monospace font. You can do this via style-Attribute.

<asp:DropDownList ID="friendDropDownList" runat="server"
style="font-family: ‘Courier New’, Courier, monospace" />

The DropDownList can be filled up in code-behind, e.g. in the Page_Load-Event. The most tricky part is to add multiple blanks. The DropDownList automatically encodes the added string to HTML and all blanks per default become one blank. That would cause the columns not to be displayed exactly below each other. One solution to this is to add blanks as a unicode escape sequence (\u00A0). The DropDownList will automatically convert these into "&#160"which can be interpreted by the browser.

protected void Page_Load(object sender, EventArgs e)
{
  PseudoFriendDataAccess da = new PseudoFriendDataAccess();
  List<Friend> friendList = da.LoadAllFriends();

  foreach (Friend f in friendList)
  {
    string text = string.Format("{0}|{1}|{2}",
      f.FirstName.PadRight(10,‘\u00A0′),
      f.LastName.PadRight(10,‘\u00A0′),
      f.BirthDay.HasValue?
      f.BirthDay.Value.ToString("dd.MM.yyyy"):
      "".PadRight(10,‘\u00A0′));
    friendDropDownList.Items.Add(
      new ListItem(text,f.ID.ToString()));
  }
}

The result for the DropDownList above feels like this:

I’ve to add that this solution via string concatenation doesn’t look really cool. So let’s take a look at other approaches.

Use third-party controls that have the multicolumn-feature

There are different third-party controls that have the multicolumn-feature. E.g. Infragistics has a WebCombo-Control that can display multiple-Columns. On Codeproject there’s also a Control availabe, but unfortunately with no source-code of the control itself: http://www.codeproject.com/KB/custom-controls/multiColsDD_List.aspx. I looked at this control, but I think it isn’t a great idea to use it for a professional application without having support and without having full source code.

So I’ve tried the Infragistics WebCombo. It worked very well up to 20 records when displaying about 5 columns. With 200 records it became very very slow in IE7. E.g. while the mouse cursor moved from item 90 to item 100, the WebCombo still showed the mouseOver-Color on item 90, then the mouseOver-Color moved slowly to item 91, 92, 93… The time used for this task was over 1 second till the mouseOver-color reached item 100. As I needed a multiple column dropdownlist with at least 200 items, the Infragistics WebCombo was no solution for me (I’ve used NetAdvantage_ASPNET_2008 Vol. 2_CLR2.x). Maybe the team of Infragistics can check this and make it faster for IE7.

So after evaluation more dropdowns from other vendors and after a phone call with Jean-Claude Trachsel, another ASP.NET-Professional@Trivadis, I decided to create a multiplecolumn-dropdownlist on my own using the AJAX Control Extenders and the build-in GridView.

Develop your one multicolumn-DropDown with AJAX Control Extenders and ASP’s GridView

Starting the development of a multicolumn-dropdown, the first thing to is is to add an UpdatePanel to your site:

<asp:UpdatePanel ID="UpdatePanel1" runat="server">
  <ContentTemplate>
    <!– all other content goes here –>
  </ContentTemplate>
</asp:UpdatePanel>

Inside the <ContentTemplate>-Tag of the UpdatePanel I place a TextBox and an ASP-Panel. The Panel’s Style is set, so that it isn’t visible per default. Below the Panel I’ve placed a DropDownExtender from the AJAX Control ToolKit. Download the Toolkit here. The DropDownExtender has a DropDownControlID- and a TargetControlID-Property. When the TargetControl is clicked (here the txtFriend-TextBox) the DropDownControl (here the FriendDropDown-Panel) becomes visible.

<asp:TextBox ID="txtFriend" runat="server"
  Width="100px" ReadOnly="true" />
<asp:Panel runat="server" ID="FriendDropDown"
  Style="display: none; visibility: hidden;">
  <!– GridView  goes here –>
</asp:Panel>
<cc1:DropDownExtender ID="DropDownExtender1" runat="server"
  DropDownControlID="FriendDropDown"
  TargetControlID="txtFriend">

As I’ve added the DropDownExtender out of Visual Studio’s ToolBox, the following Register-Directive was created automatically on my page and also an assembly-reference was set automatically.

<%@ Register Assembly="AjaxControlToolkit"
Namespace="AjaxControlToolkit" TagPrefix="cc1" %>

Next you’ve to add a GridView inside the FriendDropDown-Panel. Just drag it out of the toolbox and set the properties you need. Here the GridView is named FriendGridView. Two Eventhandlers are defined for the events RowDataBound and SelectedIndexChanged, which are necessary for this multicolumn-scenario. But before we look at the Eventhandlers in the Codebehind-file, first look at the invisibleColumn stye, which is set on the first BoundField in the GridView.

<asp:GridView ID="FriendGridView" runat="server"
  AutoGenerateColumns="false"
  OnRowDataBound="FriendGridView_RowDataBound"
OnSelectedIndexChanged="FriendGridView_SelectedIndexChanged">
  <RowStyle BackColor="#DDDDDD" />
  <Columns>
    <asp:BoundField DataField="ID"
      HeaderStyle-CssClass="invisibleColumn"
      ItemStyle-CssClass="invisibleColumn" />
    <asp:BoundField DataField="FirstName"
                    HeaderText="Firstname" />
    <asp:BoundField DataField="LastName"
                    HeaderText="Lastname" />
    <asp:BoundField DataField="Birthday"
                    HeaderText="Birthday"
                    DataFormatString="{0:dd.MM.yyyy}" />
  </Columns>
  <HeaderStyle BackColor="Blue" ForeColor="White" />
  <AlternatingRowStyle BackColor="#EEEEEE" />
  <SelectedRowStyle BackColor="#999999" />
</asp:GridView>

The FriendGridView has four columns, each bound to a property of the Friend-class. As the ID-property shouldn’t be visible to the user, the Headers and Items of this BoundField are using the CSS-class "invisibleColumn". This class simple set’s the width to zero and the display-property to none, so that this column is not visible to the user, but you can access it on a postback, e.g. to update the Friend-object in a database, where you’ll need the ID. On the page I’ve also set the font-family and font-size, as you can see below.

<style>
  .invisibleColumn
  {
    display: none;
    width: 0px;
  }
  body
  {
      font-family:Arial;
      font-size:12px;
  }
</style>

The next thing to do is to add the EventHandlers in the Codebehind-file. In the SelectedIndexChanged-Event the Text of the txtFriend-TextBox is set to the value of the second cell of the selectedRow. The second cell contains the FirstName. As the GridView is in an UpdatePanel with the TextBox, only this part of the Page is refreshed on the Clientside (via AJAX).

protected void FriendGridView_SelectedIndexChanged(…)
{
  // assign firstname
  if (FriendGridView.SelectedRow != null)
    txtFriend.Text = Server.HtmlDecode(
      FriendGridView.SelectedRow.Cells[1].Text);
  else
    txtFriend.Text = "";
}

To display some mouseover-effects on the GridView and to allow selection by clicking on a row, the RowDataBound-Eventhandler is necessary. There some Javascript is added to each row of the GridView.

protected void FriendGridView_RowDataBound(…)
{
  if (e.Row.RowType != DataControlRowType.DataRow)
    return;

 e.Row.Attributes["onmouseover"]="this.style.cursor=’hand’;"
 +"this.originalBackgroundColor=this.style.backgroundColor;"
 +"this.style.backgroundColor=’#bbbbbb’;";

 e.Row.Attributes["onmouseout"] =
 "this.style.backgroundColor=this.originalBackgroundColor;";

 e.Row.Attributes["onclick"] =
 ClientScript.GetPostBackClientHyperlink(this.FriendGridView,
  "Select$" + e.Row.RowIndex);
}

The most important on the snippet above is the last line that adds the onclick-Attribute to the row. With this attribute and the value of it the row is selected via click and doesn’t need a Select-Button, like the default-GridView needs to select a row. When a row is clicked, the SelectedIndexChanged-Event is automatically triggered by that JavaScript and the txtFriend-TextBox is set to the selected firstname in the Eventhandler for SelectedIndexChanged.

To make it really working, the last thing to do is to add the EnableEventValidation-Attribut to your page and set it to false. This allows the JavaScript from the snippet above to invoke the SelectedIndexChanged-Event. As an alternative to setting this attribute to false you can take a look at the RegisterForEventValidation-Method of ClientScriptManager that you can call in the Render-Method of your page.

<%@ Page Language="C#" EnableEventValidation="false" …

That’s all. Now let’s take a look at the dropdown. Just fill it in the Page_Load-Event with the same data as the string-concatenated dropdown before.

protected void Page_Load(object sender, EventArgs e)
{
  PseudoFriendDataAccess da = new PseudoFriendDataAccess();
  List<Friend> friendList = da.LoadAllFriends();

  FriendGridView.DataSource = friendList;
  FriendGridView.DataBind();
}

Below you see the created multicolumn-Dropdown. I’ve selected Christoph and reopened the DropDown again. The TextBox displays his firstname and the GridView shows the selected row.

ajaxExtenderWithGridViewDropDown

Make the multicolumn-DropDown usable for many rows

If you’ve more rows, the dropDownList should be scrollable. To add scrollsupport, simply extend the Style-Property of the FriendDropDown-Panel and add an overflow- and a max-height-attribut. Set the overflow-attribut to scroll, and the max-height to a value of your choice.

<asp:Panel runat="server" ID="FriendDropDown"
  Style="max-height:150px;overflow:scroll;
         display:none; visibility: hidden;">

For test-purposes I’ve just filled the FriendDropDown-GridView with more than 4 Rows to get the scroll behavior. In Firefox it looks great.

scrollableFireFoxDropDown

Unfortunately Internet Explorer 7 doesn’t calculate the size of the vertical scrollbar to the Panel (it’s a div-tag in HTML) containing the GridView. So in Internet Explorer 7 you won’t see the total of the last column. Instead of that you have to scroll horizontally.

scrollableIE7DropDown

To get very simply rid of that, I’ve added a dummy-column as the last column (and so the column on the right side) to the GridView that has a width of 15px. 15px is about the width of the vertical scrollbar.

<Columns>
<asp:TemplateField ItemStyle-Width="15px" />
</Columns>

Now that dummy-column will be behind the vertical scrollbar and the user is able to see all necessary columns.

scrollableIE7BetterDropDown

If the user scroll’s to the right with the horizontal scrollbar, he just sees the dummy-column.

scrollableIE7BetterDropDown2

So that’s all.

I think you can develop a control out of that stuff if necessary.

If you have additional information about developing multicolumn-Drowdowns or any feedback, or if you’re interested in the source code, just write a comment or a mail via the contact-formular on my homepage.

If you found this article useful, just feel free to kick it for me:

kick it on DotNetKicks.com

Thanks a lot. :-)

WPF-book is now available in stores, maybe you win a free one @MSUGS

June 30th, 2008

Since last week my German WPF-book is available in stores. You find more details about the book and some snippets of chapter 1 and chapter 14 on Galileo Computing. You can order the book on the Galileo Comuting-Website or on amazon.de and other stores.

For any questions about the book, write a comment to this post or use the contact-form of my homepage. If you’ve already got the book, I’m looking forward to your feedback.

What’s going on next:

Free MSUGS-Event about developing Custom Controls with the chance to win a WPF-book:
On Wednesday, 20th August, you can visit a free event in cooperation with the Microsoft User Group Switzerland (MSUGS) about developing Custom Controls with WPF. The event will be in Zurich @Trivadis (Europastrasse 5). You find more details about the event here. At the end of this event, you can win one WPF-Book for free.

WPF-Course @Trivadis:
If you want to know more things about WPF-Programming, take a look at the 3-day WPF-course at Trivadis, which you find here. If you take this course, you’ll get a WPF-book, the Trivadis course-material, and everything you need to become a rich & famous WPF-Programmer. ;-)

DataAccess in the time of LINQ:
Christoph Pletz and I are working on a TechnoCircle - a one day event you can visit in the second half of this year @Trivadis - about DataAccess in the time of LINQ. This TechnoCircle does not only show you how LINQ works, it shows how to implement a Data Access Layer in the time of LINQ in a Three-Layer-Architecture. It also discusses the usage of LINQ to SQL vs. Entity Framework vs. DataSets etc. As soon as you can register for the TechnoCircle, you’ll find more infos on the Trivadis-website and of course here on my blog…

Print of WPF-book will start next week

May 31st, 2008

As I promised in my last post, here are some infos about my nearly finished book project:

Last weekend I made checks on the first galley proof of my german WPF-book. Yesterday I got the second galley proof, the corrected one. The second galley proof I’ve checked yesterday evening and today. The book will have about 1125 pages filled up with pure Windows Presentation Foundation and will be printed at the end of next week.

Last week I saw that the book is already listed under the WPF-books on WindowsClient.NET. Who ever linked it up, thanks a lot for doing so:
>> http://windowsclient.net/community/books.aspx

As the corrections are made and the book will be printed next week, the upcoming weekend will be the first totally free weekend for me since one year. Two weeks ago I got a red card in a soccer match, so I’m not allowed to play the last game. So next weekend is really totally free, no soccer game and no book-writing. :-)

So what should I do this upcoming weekend? I could start writing another WPF- or Silverlight-article. But no, on that first free weekend for such a long time I won’t do that. I tell you what I’m going to do, if the weather won’t be totally bad:

About one month ago I bought a new bike (on the picture below), so I’ll test it on a tour with my family next weekend. There are several mountains and single trails directly around our home, where you can jump and ride with a lot of fun. As I know there are also many bikers at Trivadis (the company I’m working for), maybe I’ll meet some of them in a race down the hills through the great black forest

bikingThomas

Got the MCTS: .NET Framework 3.5, Windows Presentation Foundation

May 18th, 2008

Last Thursday I took the exam for the Microsoft Certified Technology Specialist .NET Framework 3.5, Windows Presentation Foundation. The exam is brand new and covers a wide spectrum of WPF.

Im not sure, if asking Multiple-choice-questions is a good thing for testing the knowledge of programmers, but hey, the exam was a good test for my German WPF-book. (I didn’t have the book with me, but it’s still in my head. Like a branding :-)).

After every question I read, I thought, if the answer of the question can be found in my book. And I’m really glad to say that, with some exceptions to specific deployment questions, everything can be found in my book. So if you know all contents and details of my book well, you won’t have any problems to pass this exam. So with the book still in my head I did it and earned my fourth MCTS:

 MCTS_Logo

By the way, I’ve finished the manuscript for my wpf book in time. Since end of April the correctors give their best and I’m sure the book will be in stores in June 2008, according to plan. Find more infos about the book-process during the next weeks on this blog.

UIAutomation to open ComboBox from Code

May 18th, 2008

In WPF there’s an Automation Framework called UIAutomation. This Framework can be used to control UIElements from code. This can be useful for different scenarios:

  • Provide the user additional help
  • Control a programm by another programm
  • Test applications
  • Execute a user-action from code

The Automation Frameowork isn’t limited to WPF. You can also control Win32-Applications.

In WPF for every FrameworkElement you find a class named like [TheElementsName]AutomationPeer. E.g. for the Button-class there’s a ButtonAutomationPeer-class, for ComboBox there’s a ComboBoxAutomationPeer-class…

Such AutomationPeer-Classes support different Patterns. E.g. the ComboBoxAutomationPeer-class supports the ExpandCollapse-Pattern to expand and collapse the ComboBox. You do this with the following snippet:

ComboBoxAutomationPeer peer =
  new ComboBoxAutomationPeer(yourComboBox);
IExpandCollapseProvider provider =
  (IExpandCollapseProvider)
  peer.GetPattern(PatternInterface.ExpandCollapse);
provider.Expand();

There’s much more you can do with UIAutomation, which is part of my German WPF-book (Chapter 19).

WPF Multi-Layer Business Application for Download

May 16th, 2008

Tomorrow Karl Shifflett is giving a Code Camp session in Charlotte. Unfortunately it’s too far away for me to participate. :-)

Today Karl has posted a really great WPF Multi-Layer Business Application that can be downloaded from his blog. Check it out here and learn from it. Thx to Karl for posting and sharing that great sample app.

LostFocus (TextBox) vs. Buttons IsDefault-Property

May 2nd, 2008

If you bind the Text-Property of a TextBox to something, the "something" is updated when the TextBox loses focus. This is the Default-UpdateSourceTrigger defined in the Metadata for the TextBox.TextProperty. In a Data Binding you can specify another UpdateSourceTrigger, like e.g. PropertyChanged.

If a TextBox has LostFocus as UpdateSourceTrigger, which is the default, you can get problems if the TextBox is inside of a Dialog that contains a OK-Button with the IsDefault-Property set to true. When the TextBox has the Focus, the user can press Enter and the Button is clicked, but the TextBox still keeps the Focus. The LostFocus-Event doesn’t occur, so the Source of a Data Binding isn’t updated with the value of the TextBoxs Text-Property. You need to update the source explicit. Let’s take an example and use the Person-class of my previous post:

public class Person : INotifyPropertyChanged
{
  private string _name;
  public string Name
  {
    get { return _name; }
    set
    {
      _name = value;
      if (PropertyChanged != null)
        PropertyChanged(this,
          new PropertyChangedEventArgs("Name"));
    }
  }
  public event PropertyChangedEventHandler PropertyChanged;
}

The Window below just contains a TextBox and a Button. The Text-Property of the TextBox is bound to the Name of the data in the DataContext. This would be a Person-instance, as you’ll see below in the codebehind-file. The Button has it’s IsDefault-Property set to true and defines an eventhandler for the Click-Event.

<Window x:Class="LostFocusTest.Window1" …
  xmlns:local="clr-namespace:LostFocusTest"
  Title="Focus/IsDefault" Width="200" SizeToContent="Height">
  <StackPanel>
    <TextBox Margin="5" Text="{Binding Name}"/>
    <Button Content="OK" IsDefault="True"
       Click="Button_Click"/>
  </StackPanel>
</Window>

In the Constructor in the Codebehind-file a Person-instance is created. It’s assigned to the Windows DataContext-Property, so the TextBox above will display the Persons name, which is set to "Thomas". The Click-Eventhandler for the Button simply displays the name of the Person in a MessageBox.

public partial class Window1 : Window
{
  private Person _pers;
  public Window1()
  {
    InitializeComponent();
    _pers = new Person();
    _pers.Name = "Thomas";
    this.DataContext = _pers;
  }

  private void Button_Click(object sender, RoutedEventArgs e)
  {
    MessageBox.Show(_pers.Name);
  }
}

If I start the application and type "Urs" into the TextBox and press Enter, the Button is clicked but the TextBox keeps the focus. So the Source, which is the Person-Instance, isn’t updated and the MessageBox still displays the old value (”Thomas”), as you can see in the Image below:

LostFocus vs. IsDefault

For such a scenario, you have to update the source explicit. You could do this in the Click-Eventhandler. To update the source, you have to get the BindingExpression for the TextProperty. You get the BindingExpression by calling the GetBindingExpression-Method on the TextBox. Pass in the Text-Property as parameter. On the BindingExpression call the UpdateSource-Method to update the Person-instance explicitly with the value defined in the Text-Property of the TextBox. With the Eventhandler below the Person-Instance would always be actualized when the Button is clicked. The MessageBox would display the right value:

private void Button_Click(object sender, RoutedEventArgs e)
{
  TextBox textBox = Keyboard.FocusedElement as TextBox;
  if (textBox != null)
  {
    BindingExpression be =
      textBox.GetBindingExpression(TextBox.TextProperty);
    if (be != null)
      be.UpdateSource();
  }
  MessageBox.Show(_pers.Name);
}

Just kick it for me:

kick it on DotNetKicks.com

The dream of "half-automatic" Automation Properties

May 2nd, 2008

Everyone who has worked with WPF knows the interface INotifyPropertyChanged. It only defines the PropertyChanged-event, that should be called when a property’s value has been changed. The PropertyChanged-event is used by WPF’s Data Binding.

Normally a class fires the event in the set-Accessors of its properties. And that’s the problem why you can’t use Automation Properties for classes that implement INotifyPropertyChanged.

Let’s take a very simple example, a Person-class, that only contains a Name-Property:

public class Person
{
  public string Name { get; set; }
}

If you now want to implement INotifyPropertyChanged, you have to use a property backed explicitly with a private field:

public class Person:INotifyPropertyChanged
{
  private string _name;
  public string Name
  {
    get { return _name; }
    set
    {
      _name = value;
      if (PropertyChanged != null)
        PropertyChanged(this,
          new PropertyChangedEventArgs("Name"));
    }
  }
  public event PropertyChangedEventHandler PropertyChanged;
}

Wouldn’t it be nice to use a "half-automatic"-Property in the code-snippet above? The private-Field _name and the get-Accessor could be created. A keyword would be necessary to access the private-Field in the set-Accessor. I think the keyword could be autoField or something like that. If Microsoft would implement "half automatic"-Properties in C# 3.5 or 4.0, you could create the Person-class as below. But keep in mind that this is just a dream, I don’t know if something like this is planned, so the Person-class implemented like below wouldn’t work (today):

public class Person:INotifyPropertyChanged
{
  public string Name {
    get;
    set
    {
      autoField = value;
      if (PropertyChanged != null)
        PropertyChanged(this,
          new PropertyChangedEventArgs("Name"));
    }
  }

  public event PropertyChangedEventHandler PropertyChanged;
}

What do you think of “half-automatic”-Properties? Would it be a useful feature for you?

Vista’s SaveFileDialog and OpenFileDialog in WPF

April 12th, 2008

Windows Vista contains new Win32-Dialogs to save and open a file. There are also the old dialogs from XP available.

Windows Presentation Foundation has two wrapper-classes for Win32-Dialogs. The Microsoft.Win32-Namespace contains a SaveFileDialog- and an OpenFileDialog-class. The classes are located in the PresentationFramework-Assembly, one of the central assemblies of WPF.

When you use the classes from Microsoft.Win32-Namespace, you get the old dialogs from XP. In the snippet below the OpenFileDialog is opened.

Microsoft.Win32.OpenFileDialog dlg =
  new Microsoft.Win32.OpenFileDialog();
dlg.ShowDialog()

With the two lines above the dialog below is shown, and that’s the old-style Windows XP OpenFileDialog:

image

Windows Forms also wraps the two Dialogs SaveFileDialog and OpenFileDialog with classes in the namespace System.Windows.Forms. Add a reference to the assembly System.Windows.Forms.dll to your WPF-Project, and you can use these wrapper-classes. The interesting part is that they show per default the new Vista Dialog.

System.Windows.Forms.OpenFileDialog dlg =
  new System.Windows.Forms.OpenFileDialog();
dlg.ShowDialog();

With the lines above the new Vista Dialog is displayed:

image

Both WinForms-Dialog-Classes contain a property called AutoUpgradeEnabled (inherited from FileDialog, property is supported in .NET Versions 3.5, 3.0 SP1 and 2.0 SP1). This property is per default true, so the FileDialog-Instance will automatically upgrade appearance and behavior when running on Windows Vista. Set it to false, to get the old dialog-style:

System.Windows.Forms.OpenFileDialog dlg =
  new System.Windows.Forms.OpenFileDialog();
dlg.AutoUpgradeEnabled = false;
dlg.ShowDialog();

On XP, the AutoUpgradeEnabled-property doesn’t have any effect, of course, there’s only the old dialog available.

Fazit: The cool thing about Microsoft.Win32 is that you can add a using-directive to your WPF-Project and use the classes inside that namespace without a full qualified name. Adding a using-directive for System.Windows.Forms isn’t a good thing in a WPF-Project. There are many double-matches in System.Windows.Forms and e.g. WPF’s System.Windows.Controls-Namespace, like e.g. the Button-class. So the compiler needs full qualified names. But if you wan’t to use the new Dialogs, you have to use the Wrappers from Windows Forms, but don’t add a using-directive for System.Windows.Forms, use full qualified names instead.

There are also other possibilities to get the new vista dialogs. E.g. you could make a Win32-call into comdlg32.dll, but the already available wrappers from Windows Forms are the easiest and fastest way to do it. And you won’t program something, if it’s already there, right? But you have to know that it is there. 8-)

I think Microsoft will update the classes in Microsoft.Win32 in the near future, maybe in the upcoming servicing release for .NET 3.5 planned for Summer 2008? It’s really a little bit strange, WPF is the technology to create first class Vista apps, and its wrappers show still old dialogs, while Windows Forms wrappers don’t…