Archive

Archive for the ‘.NET’ Category

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

Explicitly update binding sources

January 16th, 2008

In WPF data binding scenarios, the binding source is usually updated implicitly – if you, for example, edit the text of a bound TextBox control, the underlying binding source is updated a soon as the control loses focus.

This is something you might want to prevent sometimes – a common scenario is a model dialog that provides a Cancel button to abort changes. The basic idea is that the underlying data remains unchanged until you commit all your changes at once if the dialog’s OK button is clicked.

The solution to prevent automatic updates of the binding source is to set the UpdateSourceTrigger property to Explicit, which prevents automatic updates of the underlying data item:

<TextBox Text="{Binding Path=Name, UpdateSourceTrigger=Explicit}" />

However, this feature comes with a catch: You’ll have to trigger updates on all your controls manually. Beatriz Costa posted a generic solution, but I found it a bit tedious to explicitly update every single control on my dialog. As a result, I came up with a solution that recursively processes a visual tree from a given starting point and updates all controls that provide one or several bindings of your choice:

/// <summary>
/// Recursively processes a given dependency object and all its
/// children, and updates sources of all objects that use a
/// binding expression on a given property.
/// </summary>
/// <param name="obj">The dependency object that marks a starting
/// point. This could be a dialog window or a panel control that
/// hosts bound controls.</param>
/// <param name="properties">The properties to be updated if
/// <paramref name="obj"/> or one of its childs provide it along
/// with a binding expression.</param>
public static void UpdateBindingSources(DependencyObject obj,
                          params DependencyProperty[] properties)
{
  foreach (DependencyProperty depProperty in properties)
  {
    //check whether the submitted object provides a bound property
    //that matches the property parameters
    BindingExpression be =
      BindingOperations.GetBindingExpression(obj, depProperty);
    if (be != null) be.UpdateSource();
  }

  int count = VisualTreeHelper.GetChildrenCount(obj);
  for(int i=0; i<count; i++)
  {
    //process child items recursively
    DependencyObject childObject = VisualTreeHelper.GetChild(obj, i);
    UpdateBindingSources(childObject, properties);
  }
}

Using the above method is quite simple: Just set a starting point (window, grid, whatever) along with an arbitrary number of dependency properties you’d like to have processed. As an example: The snipped below commits all bound Text properties of a dialog’s TextBox controls as well bound items of XamComboEditor dropdown controls:

//update TextBox and ComboBox controls of the dialog
DependencyProperty dpText = TextBox.TextProperty;
DependencyProperty dpSelectedItem = XamComboEditor.SelectedItemProperty;
UpdateBindingSources(this, dpText, dpSelectedItem);
Author: Categories: WPF Tags: , ,