Archive

Archive for the ‘WPF’ Category

Kaxaml source on CodePlex

January 27th, 2008

Robby Ingebretsen published the source code of his incredibly useful (and beautiful!) Kaxaml on CodePlex. I often prefer Kaxaml over Visual Studio because it combines a bunch of really smart features with a very nice UI that just makes it a pleasure to work with. I’m definitely looking forward to have a peek at its internals 🙂

CodePlex project site: http://www.codeplex.com/Kaxaml
Official Kaxaml download site: http://www.kaxaml.com

Author: Categories: Open Source, Tools, WPF Tags: , , ,

A versatile WPF TreeView control

January 24th, 2008

A tutorial is now available on Code Project, so check the article for a detailed overview. And please leave your rating if you like the control 🙂
http://www.codeproject.com/KB/WPF/versatile_treeview.aspx

Update: The latest version is currently only available through the download link below. I’ll update the CodeProject article once the current filtering mechanism has been rewritten:

Download: wpf-treeview.zip (Current version: 1.0.7, updated 2008.04.06)

TreeView example This is a little something I’ve been working on for a while: A replacement (or better: enhancement) of WPF’s built-in TreeView control.

I became aware of the default control’s limitations during my last project – I naturally started with hierarchical data templates, but was soon confronted with quite a few issues: I missed a simple API to control the tree, and styling of the tree’s nodes proved hard as well. Furthermore, WPF’s TreeView tends to fire all sorts of SelectedItemChanged events if it’s being refreshed or rebound, which caused side-effects with TwoWay data binding.

However, instead of posting a rant that probably nobody would ever read (let alone care about), I worked on an alternative. Here’s the tree’s main features at a glance:

  • Simple declaration:
    <local:ProductTree x:Name="MyTree"
                       Items="{Binding Source={StaticResource Shop},
                              Path=Products}"
                       SelectedItem="{Binding ElementName=MyProductList,
                              Path=ActiveItem, Mode=TwoWay}"
                       NodeContextMenu="{StaticResource CategoryMenu}"
                       TreeNodeStyle="{StaticResource SimpleFolders}"
                       TreeStyle="{StaticResource SimpleTreeStyle}"
                       SelectedItemChanged="OnSelectedItemChanged"
    />
  • Simple and type safe API:
    //bind flat list of business objects to tree
    List<Product> products = GetProducts();
    myTree.Items = products;
    
    //select a given item
    Product foo = GetBestSellingProduct();
    myTree.SelectedItem = foo; 
    
    //SelectedItem is of type Product - no casts required
    Product bar = myTree.SelectedItem;
  • Lazy loading support – does not create tree nodes until the parent node is expanded. Also provides the option to automatically clear invisible tree nodes. This allows either virtualized trees in case getting data is expensive, or low memory trees that keep the number of tree nodes at a minimum.
  • Simple sorting.
  • Convenient context menu handling for tree nodes
  • Optional root node which is not dependent on the tree’s bound items
  • Simple styling on every level: Tree, TreeViewItem, or bound items (via DataTemplates).
  • Tree layout can be cached, saved and reapplied.
  • Access to tree nodes (TreeViewItem) through bound items.
  • AutoCollapse feature / ExpandAll / CollapseAll methods

All this goodness comes at a price: The TreeViewBase class that provides this functionality, is abstract. This means you have to write a little code yourself. However, you’ll probably manage with 3 lines of code, as the base control just needs to know 3 things:

  • How to generate an identifier for a given tree node
  • How to access a bound item’s childs, if there are any
  • How to access a bound item’s parent, if there is one

Here’s the complete implementation of the sample application’s tree control:

//a tree control that handles only ShopCategory objects
public class CategoryTree : TreeViewBase<ShopCategory>
{

  //the sample uses the category's name as the identifier
  public override string GetItemKey(ShopCategory item)
  {
    return item.CategoryName;
  }

  //returns subcategories that should be available through the tree
  public override ICollection<ShopCategory>
                             GetChildItems(ShopCategory parent)
  {
    return parent.SubCategories;
  }

  //get the parent category, or null if it's a root category
  public override ShopCategory GetParentItem(ShopCategory item)
  {
    return item.ParentCategory;
  }

I’m planning to write a CodeProject article for this one, but for now, it’s only available through my place without a tutorial. However: The library comes with a sample project that shows pretty much all features of the control. Project format is currently VS2008 only, but binaries which target .NET 3.0 are included. Enjoy!

Sample Application

Loaded event of a WPF control may be fired repeatedly

January 21st, 2008

In all my Windows Forms applications, I usually start with a common base class for forms and controls that provides a bunch of convenience properties, subscribes to common events, handles proper cleanup etc. I also implement an empty virtual InitControl method which can be overridden by deriving controls to initialize themselves.

As you can see in the Windows Forms snippet below, InitControl is being called right after the control’s Load event has been fired:

/// <summary>
/// Inits the base class and registers event listeners.
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{     
  base.OnLoad(e);
  
  if (!DesignMode)
  {
    InitControlInternal();       
    InitControl();
    initControlCompleted = true;
  }
}


/// <summary>
/// An empty template method which is being invoked after the
/// control has been loaded during <see cref="OnLoad"/>.
/// </summary>
/// <remarks>The base class does not invoke this method if
/// the control is in design mode.</remarks>
protected virtual void InitControl()
{
  //this method is supposed to be overridden. Initialization of
  //the base class itself happens in InitControlInternal
}

 

Naturally, I kept this practice in WPF using the Loaded event which is available for all WPF controls. But to my surprise, InitControl method was getting called repeatedly while I expected it to be called just once, which causes some controls to be re-initialized over and over again. The reason in my case was a TabControl that hosted my user controls. As it turned out, TabControl unloads/reloads user controls with every tab switch.

Unfortunately, there seems to be no common solution to this very problem – you will have to decide how to handle Loaded events specifically for your initialization logic. However:

  • Using Loaded may not be problem in a lot of scenarios, but keep in mind that you might run in trouble when depending on it, especially with a reusable control.
  • You can use the Initialized event of a control rather than Loaded. Check the API documentation for a description of the two events.
  • Use a boolean field to track whether your initialization code has alreay been invoked:

    protected override void InitControl()
    {
      if (initControlCalled) return;
    
      initControlCalled = true;
      //init control
      ...
    }

 

I’ve implemented a short sample that demonstrates the issue. Basically, it’s a tab control that hosts a user control on one of its tab items:

<TabControl>
  <TabItem Header="Tab 1">
    <!-- the user control that counts Loaded events -->
    <local:LoadedCounter />
  </TabItem>

  <TabItem Header="Tab 2">
    <TextBlock>Switch back to trigger event in tab 1.</TextBlock>
  </TabItem>
</TabControl>

 

Once you switch back and forth, you can see that Loaded is being invoked with every switch:

TabControl

Download Sample Project (VS2008)

Author: Categories: WPF Tags: ,

Simplify MessageBox handling with WPF

January 18th, 2008

This is really trivial, but I’ve always used a similar helper class for my WinForms apps, and it was something I immediately missed when starting my first WPF project. So I thought I should share it with you – a simple helper class to display message boxes without having to worry about a lot of parameters just to show a message with a title and an icon.

This is basically just a façade to the standards MessageBox class, but more convenient. As an example, if you want to show a message box with a warning icon, you currently have to submit quite a few parameters:

string msg = "This is a warning.";
string title = "My Application";
MessageBox.Show(msg, title, MessageBoxButton.OK, MessageBoxImage.Warning);


With the Dialogs helper class, you can get the same result quite painless:

Dialogs.ShowWarning("This is a warning.");

The class provides most common operations, including Yes/No message boxes, and if you need more overloads, adding them isn’t really a problem.

Dialogs Helper Class

One last note: As you can see in the class diagram, the class contains a hard coded ApplicationName field which is used for the dialog’s title: This is bad practice. I’d recommend to create a string in Resources.resx, remove the field, and update the four or five references to the field accordingly.

using System.Windows;

namespace Evolve.Wpf.Samples
{
  /// <summary>
  /// Provides convenience methods to display message boxes.
  /// </summary>
  public static class Dialogs
  {
    //TODO rather put a string in a resource file - it's just cleaner
    public static string ApplicationName = "Change ApplicationName in Dialogs.cs";


    /// <summary>
    /// Displays an error dialog with a given message.
    /// </summary>
    /// <param name="message">The message to be displayed.</param>
    public static void ShowError(string message)
    {
      ShowMessage(message, MessageBoxImage.Error);
    }


    /// <summary>
    /// Displays an error dialog with a given message.
    /// </summary>
    /// <param name="message">The message to be displayed.</param>
    public static void ShowInformation(string message)
    {
      ShowMessage(message, MessageBoxImage.Information);
    }


    /// <summary>
    /// Displays an error dialog with a given message.
    /// </summary>
    /// <param name="message">The message to be displayed.</param>
    public static void ShowWarning(string message)
    {
      ShowMessage(message, MessageBoxImage.Warning);
    }


    /// <summary>
    /// Displays an error dialog with a given message and icon.
    /// </summary>
    /// <param name="message">The message to be displayed.</param>
    /// <param name="icon">The icon to be displayed with the message.</param>
    public static void ShowMessage(string message, MessageBoxImage icon)
    {
      string appName = ApplicationName;
      MessageBox.Show(message, appName, MessageBoxButton.OK, icon);
    }


    /// <summary>
    /// Displays an OK / Cancel dialog and returns the user input.
    /// </summary>
    /// <param name="message">The message to be displayed.</param>
    /// <param name="icon">The icon to be displayed.</param>
    /// <returns>User selection.</returns>
    public static MessageBoxResult ShowOkCancel(string message, MessageBoxImage icon)
    {
      string appName = ApplicationName;
      return MessageBox.Show(message, appName, MessageBoxButton.OKCancel, icon);
    }


    /// <summary>
    /// Displays a Yes/No dialog and returns the user input.
    /// </summary>
    /// <param name="message">The message to be displayed.</param>
    /// <param name="icon">The icon to be displayed.</param>
    /// <returns>User selection.</returns>
    public static MessageBoxResult ShowYesNo(string message, MessageBoxImage icon)
    {
      string appName = ApplicationName;
      return MessageBox.Show(message, appName, MessageBoxButton.YesNo, icon);
    }


    /// <summary>
    /// Displays an Yes / No / Cancel dialog and returns the user input.
    /// </summary>
    /// <param name="message">The message to be displayed.</param>
    /// <param name="icon">The icon to be displayed.</param>
    /// <returns>User selection.</returns>
    public static MessageBoxResult ShowYesNoCancel(string message, MessageBoxImage icon)
    {
      string appName = ApplicationName;
      return MessageBox.Show(message, appName, MessageBoxButton.YesNoCancel, icon);
    }
  }
}
Author: Categories: WPF Tags: ,

Multithreaded WPF Progress Dialog

January 17th, 2008

With this WPF progress dialog, you can display a progress window and invoke a method on a background thread with just a few lines of code. Let’s say, you have a worker method called CountTo100, then all you need to get things running is this:

//create a dialog instance
ProgressDialog dlg = new ProgressDialog();
dlg.Owner = this;
dlg.DialogText = "hello world";

//we cannot access the user interface on the worker thread, but we
//can submit an arbitrary object to the RunWorkerThread method
int startValue = int.Parse(txtStartValue.Text);

//start processing and submit the start value
dlg.RunWorkerThread(startValue, CountTo100);
 

RunWorkerThread displays the dialog as a modal window, and invokes CountTo100 on a background thread. Styling of the dialog is completely up to you, but here’s a screenshot of the dialog running in the sample application:

progressbar-sample

The dialog uses a BackgroundWorker component and supports updating both progress bar and displayed text directly from the worker thread. Cancelling support, returning results from the worker thread and simplified exception handling are available as well. In order to get you started in no time, I’ve created a little sample application that shows a few scenarios, including parameter submission and the handling of exceptions on the worker thread. Enjoy! 🙂

Download Sample (VS2008 / VS2005 projects included): wpfprogressdialog.zip

Author: Categories: Open Source, WPF Tags: , ,

ReSharper Code Snippet for Dependency Properties

January 17th, 2008

This is a ReSharper code snippet I’ve been using quite a lot lately – it allows you to easily create a WPF dependency property along with event handlers, documentation, and initialization code. Here’s a sample:

#region MyStringProperty dependency property

/// <summary>
/// This is a sample string property.
/// </summary>
public static readonly DependencyProperty MyStringPropertyProperty;

//TODO: copy to static constructor
//register dependency property
//FrameworkPropertyMetadata md = new FrameworkPropertyMetadata("hello world", MyStringPropertyPropertyChanged);
//MyStringPropertyProperty = DependencyProperty.Register("MyStringProperty", typeof (string), typeof (MyControl), md);                                                      


/// <summary>
/// A property wrapper for the <see cref="MyStringPropertyProperty"/>
/// dependency property:<br/>
/// This is a sample string property.
/// </summary>
public string MyStringProperty
{
  get { return (string) GetValue(MyStringPropertyProperty); }
  set { SetValue(MyStringPropertyProperty, value); }
}


/// <summary>
/// Handles changes on the <see cref="MyStringPropertyProperty"/> dependency property. As
/// WPF internally uses the dependency property system and bypasses the
/// <see cref="MyStringProperty"/> property wrapper, updates should be handled here.
/// </summary>
/// <param name="d">The currently processed owner of the property.</param>
/// <param name="e">Provides information about the updated property.</param>
private static void MyStringPropertyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
  MyControl owner = (MyControl) d;
  string newValue = (string) e.NewValue;

  //TODO provide implementation
  throw new NotImplementedException("Change event handler for dependency property MyStringProperty not implemented.");
}

#endregion

Just import the attached snippet into ReSharper, then type dpp in Visual Studio to trigger the template.

BTW: If you’re using VS without ReSharper but need snippets for dependency properties, routed events or routed commands, Dr. WPF has the cure.

Download File: dpp-snippet.xml