Losing your identity

Recently I’ve had time to revisit the question of identity columns (or sequences if you like). A client had come up with a screen that they really wanted us to incorporate in to their application, and the design of it had been done by some of their business analysts. One of the fields that was present on the screen was a unique identifier. Now, being a bit of a nosy so and so, I wanted to know where the unique identifier came from and was told that it was just an identify column padded out to 9 digits with the letter C in front of it (apparently C stood for client). This lead me to have an interesting discussion with the analysts:

Me: Why are we taking up valuable screen real estate with this field?
Analyst: It’s on there so the user knows the id of the customer.
Me: Fair enough. Can they search on this field?
Analyst: No.
Me: Does the client know their id value?
Analyst: No
Me: So, what purpose does this field have?
Analyst (in a sneering tone): It’s there to ensure referential integrity, and to give us a unique value to update the client on. Don’t you know anything about relational design?

Now, at this point, you might imagine that I was less than pleased with the design based on my questioning it, but why was I so put off by this field? First of all, when you are designing a screen, you have to ask yourself what the user will be doing with the screen. How will they interact with it? What do you need to put on there to let the user do their job? By putting an identifier on the screen that had no other purpose than to hold the identifier they were going to update the record against, the analysts had made a classic UI design. This, by the way, is why you need to have a User experience expert on your project, and why users, not just analysts, should have input into the UI.

By putting this field onto the screen, the analyst had given it an importance that it didn’t have. It’s a distraction for the user; always try to put on the screen the information that they need to do their job, and give them an easy flow through to discover additional information if they need it. With newer technologies like Silverlight and WPF, it’s incredibly easy to design attractive screens that show and hide information in visually appealing ways, so it’s a shame not to take advantage of these features while you can.

Don’t get me wrong, there can be a case for putting identifiers on a screen. If the user can search on the identifier, or the client could be reasonably expected to know the identifier, then it’s perfectly valid to have these on the screen. Nine times out of ten though, if the value is an auto-generated identity or sequence and it’s sole purpose is to enable referential integrity, then you don’t need to display it.

Please remember, when you have a piece of UI design in front of you, question everything. Ask why things are taking up valuable screen real estate. Ask if there are other options, such as flyouts, that could be used to present the additional information in none-intrusive ways. Most importantly of all, ask the users what they need to see – they are the experts after all.

Advertisements

Scratching that old itch.

First of all, I must apologise that it’s been so long since I last blogged. It’s been an insanely busy time for me (and I don’t mean that I’ve been coding with my underpants on my head). As you may be aware, I’m a big fan of Blend behaviours, so I thought that I’d take the time to revisit an old favourite of mine. To that end, I present all the code you’ll need to create a watermarked textbox.

namespace Goldlight.Extensions.Behaviors
{
  using System.Windows.Interactivity;
  using System.Windows.Controls;
  using System.Windows.Media;
  using System.Windows;

  public class WatermarkTextBoxBehavior : Behavior<TextBox>
  {
    protected override void OnAttached()
    {
      base.OnAttached();
      AssociatedObject.LostFocus += new RoutedEventHandler(LostFocus);
      AssociatedObject.GotFocus += new RoutedEventHandler(GotFocus);
      SetWatermark();
    }

    protected override void OnDetaching()
    {
      base.OnDetaching();
      AssociatedObject.LostFocus -= new RoutedEventHandler(LostFocus);
      AssociatedObject.GotFocus -= new RoutedEventHandler(GotFocus);
    }
    /// <summary>
    /// Get or set the brush to use as the foreground.
    /// </summary>
    public Brush WatermarkForeground { get; set; }
    /// <summary>
    /// Get or set the brush to use as the background.
    /// </summary>
    public Brush WatermarkBackground { get; set; }
    /// <summary>
    /// Get or set the text to apply as the watermark.
    /// </summary>
    public string WatermarkText { get; set; }

    /// <summary>
    /// Reset the colours of the textbox.
    /// </summary>
    private void SetStandard()
    {
      AssociatedObject.ClearValue(TextBox.ForegroundProperty);
      AssociatedObject.ClearValue(TextBox.BackgroundProperty);

      if (AssociatedObject.Text == WatermarkText)
      {
        AssociatedObject.Text = string.Empty;
      }
    }
    /// <summary>
    /// Set the watermark colours for the textbox.
    /// </summary>
    private void SetWatermark()
    {
      if (WatermarkForeground != null)
      {
        AssociatedObject.Foreground = WatermarkForeground;
      }
      if (WatermarkBackground != null)
      {
        AssociatedObject.Background = WatermarkBackground;
      }
      AssociatedObject.Text = WatermarkText;
    }
    void GotFocus(object sender, RoutedEventArgs e)
    {
      SetStandard();
    }
    void LostFocus(object sender, RoutedEventArgs e)
    {
      CheckText(AssociatedObject.Text);
    }
    private void CheckText(string value)
    {
      if (string.IsNullOrWhiteSpace(value))
      {
        SetWatermark();
      }
      else
      {
        SetStandard();
      }
    }
  }
}

The code is pretty straightforward. When the textbox receives focus, if it contains just the Watermark text, the watermark text is cleared out and the original foreground and background brushes are restored. When the textbox loses focus, if it’s empty the watermark text is displayed and the watermark fore and background brushes are set. Now, for the clever bit, because we’re updating the textbox text directly we aren’t going to be updating any underlying binding

Draggable PushPins

I must apologise that it has taken me so long to post a blog entry. I’ve been busy playing about with code contracts and working with Bing Maps in Silverlight – there’s been a lot for me to take in. Actually, the Bing maps part is the reason for this posting, and I hope that it really helps you out.

A common requirement in GIS applications is to take a point of interest from one location and move it to another by dragging it. This is behaviour that you would expect to be standard, but surprisingly enough it is not present with a default Pushpin in Silverlight Bing maps. In this post, we’ll discuss adding a Blend Behavior that provides this drag and drop functionality.

As usual, when writing a behavior, you start off by inheriting from the generic Behavior class, telling it which framework element you want to associate the behavior with.

public class DraggablePushpin : Behavior<Pushpin>
{
}

Now we want to tell it what happens when we attach the object. This is done in the OnAttached override.

/// <summary>
/// Hook the event handlers to this instance.
/// </summary>
protected override void OnAttached(){
base.OnAttached();
 AssociatedObject.MouseLeftButtonDown +=
new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
}

Basically, when the left mouse button is pressed on the Pushpin, we’re going to invoke an event handler that is going to do the grunt work for handling the relevant events that we need to work with. The definition of this method looks like this:

/// <summary>
/// Called when the left mouse button is pressed on a
/// Point of Interest.
/// </summary>
void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (_map == null)
// Find the map this pushpin is attached to.
_map = FindParent<Map>(AssociatedObject);
  if (_map != null)
{
if (this.ParentMapMousePanHandler == null)
{
this.ParentMapMousePanHandler = new EventHandler<MapMouseDragEventArgs>
((s, epan) => epan.Handled = this._isdragging);
_map.MousePan += ParentMapMousePanHandler;
}
if (this.ParentMapMouseLeftButtonEventHandler == null)
{
this.ParentMapMouseLeftButtonEventHandler = new MouseButtonEventHandler
((s, args) => ConfirmMoveLocation());
_map.MouseLeftButtonUp += this.ParentMapMouseLeftButtonEventHandler;
}
if (this.ParentMapMouseMoveHandler == null)
{
// If the mouse is performing a drag operation, convert the
// underlying location based on the position of the mouse
// on the viewport to a map based location.
this.ParentMapMouseMoveHandler = new MouseEventHandler(
(s, mouseargs) =>
{
if (_isdragging)
_location = _map.ViewportPointToLocation(mouseargs.GetPosition(_map));
});
_map.MouseMove += this.ParentMapMouseMoveHandler;
}
}
_isdragging = true;
}

This method starts off by identifying the map that owns the pushpin. This means traversing the visual tree until the map is identified (I’ve done this because a common way of allocating Pushpins to a map is to host them in a DataTemplate which causes problems when attempting to find the parent map just by methods on the Pushpin). Once the map has been identified, we are going to handle the following map events:

Mouse pan
Mouse left button up
Mouse move.

When the mouse pans, the event handler uses a flag to determine whether or not a Pushpin is being dragged and sets the Handled parameter as necessary.

When the mouse moves, the event handler converts the position of the mouse on the map into a location coordinate.

When the left button is released, the behavior calls a method to prompt the user whether or not they wish to move the location and updates the position accordingly.
Finally, we have methods available to detach the events. The whole behaviour is shown here:

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Interactivity;
using Microsoft.Maps.MapControl;
using Microsoft.Maps.MapControl.Core;
namespace Pointilist.Behaviors{
/// <summary>
/// This behaviour adds drag capabilities to a Bing Maps <see cref="Pushpin"/> control.
/// </summary>
public class DraggablePushpin : Behavior<Pushpin>
{
#region Members
private bool _isdragging = false;
private MapBase _map = null;
private EventHandler<MapMouseDragEventArgs> ParentMapMousePanHandler;
private MouseButtonEventHandler ParentMapMouseLeftButtonEventHandler;
private MouseEventHandler ParentMapMouseMoveHandler;
private Location _location;
#endregion
    /// <summary>
/// Hook the event handlers to this instance.
/// </summary>
protected override void OnAttached()
{
base.OnAttached();
      AssociatedObject.MouseLeftButtonDown +=
new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
    }
    /// <summary>
/// Unhook the events when this is detaching.
/// </summary>
protected override void OnDetaching()
{
base.OnDetaching();
      AssociatedObject.MouseLeftButtonDown -=
new MouseButtonEventHandler(AssociatedObject_MouseLeftButtonDown);
      DetachEvents();
}

    /// <summary>
/// Make sure that no mouse events are left dangling.
/// </summary>
private void DetachEvents()
{
if (_map == null) return;
if (this.ParentMapMousePanHandler != null)
{
_map.MousePan -= ParentMapMousePanHandler;
ParentMapMousePanHandler = null;
}
if (ParentMapMouseLeftButtonEventHandler != null)
{
_map.MouseLeftButtonUp -= ParentMapMouseLeftButtonEventHandler;
ParentMapMouseLeftButtonEventHandler = null;
}
if (ParentMapMouseMoveHandler != null)
{
_map.MouseMove -= ParentMapMouseMoveHandler;
ParentMapMouseMoveHandler = null;
}
}
    /// <summary>
/// Only move the poi if the user accepts the change
/// (at which point, it's saved to the database).
/// </summary>
private void ConfirmMoveLocation()
{
_isdragging = false;
if (_location == null) return;

      DetachEvents();
      MessageBoxResult result = MessageBox.Show("Are you sure you want to move here?",
"Move location?", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK)
{
AssociatedObject.Location = _location;
}
      _location = null;
}
    /// <summary>
/// Called when the left mouse button is pressed on a
/// Point of Interest.
/// </summary>
void AssociatedObject_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (_map == null)
// Find the map this pushpin is attached to.
_map = FindParent<Map>(AssociatedObject);
      if (_map != null)
{
if (this.ParentMapMousePanHandler == null)
{
this.ParentMapMousePanHandler = new EventHandler<MapMouseDragEventArgs>
((s, epan) => epan.Handled = this._isdragging);
_map.MousePan += ParentMapMousePanHandler;
}
if (this.ParentMapMouseLeftButtonEventHandler == null)
{
this.ParentMapMouseLeftButtonEventHandler = new MouseButtonEventHandler
((s, args) => ConfirmMoveLocation());
_map.MouseLeftButtonUp += this.ParentMapMouseLeftButtonEventHandler;
}
if (this.ParentMapMouseMoveHandler == null)
{
// If the mouse is performing a drag operation, convert the
// underlying location based on the position of the mouse
// on the viewport to a map based location.
this.ParentMapMouseMoveHandler = new MouseEventHandler(
(s, mouseargs) =>
{
if (_isdragging)
_location = _map.ViewportPointToLocation(mouseargs.GetPosition(_map));
});
_map.MouseMove += this.ParentMapMouseMoveHandler;
}
}
_isdragging = true;
}
    /// <summary>
/// Find the relevant parent item for a particular dependency object.
/// </summary>
/// <typeparam name="T">The type of object to search for.</typeparam>
/// <param name="child">The <see cref="DependencyObject"/> to start searching from.</param>
/// <returns>The parent object if found, null otherwise.</returns>
public static T FindParent<T>(DependencyObject child) where T : FrameworkElement
{
DependencyObject parentObject = VisualTreeHelper.GetParent(child);
      // If parentObject is null, we've reached the top of the tree without finding the item we were looking for.
if (parentObject == null) return null;
      T parent = parentObject as T;
// If parent is null, recursively call this method.
if (parent == null)
return FindParent<T>(parentObject);
      // If we reach this point, we have found the parent item we are looking for.
return parent;
}
}
}

Now, it’s a simple matter to hook it up to a Pushpin.

<m:Pushpin m:MapLayer.Position="{Binding Location, Mode=TwoWay}"
Visibility="{Binding IsVisible, Converter={StaticResource VisibilityConverter}}"
PositionOrigin="Center" ToolTipService.ToolTip="{Binding Address}">
<interact:Interaction.Behaviors>
<behavior:DraggablePushpin />
</interact:Interaction.Behaviors>
</m:Pushpin>

There you have it – a draggable Pushpin. I hope that this helps you as much as it’s helping me.

Silverlight charts, and reaching my inner child

So, there was a question in the Code Project forums today from somebody looking to create an application that uses input data, LINQ and charting. My first reaction was, “we don’t provide code for people; it’s not rentacoder”, but I took pity on the poor so and so. To that end, I decided to knock together a quick sample for him that hopefully will get the point across to him. Here’s the code in all it’s glory.

First of all, here’s a quick class that I’m going to use to simulate the database table:

using System;

namespace GraphingSample
{
  public class LinqDataSample
  {
    public string Name { get; set; }
    public int Value { get; set; }
  }
}

Hey, I’m not going to do all the hard work and create the whole solution.;->

Here’s the source for the control:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;

namespace GraphingSample
{
  public partial class MainPage : UserControl
  {
    private ObservableCollection<LinqDataSample> _data = new ObservableCollection<LinqDataSample>();
    public MainPage()
    {
      InitializeComponent();

      AddData(10, "Josh");
      AddData(20, "Colin");
      AddData(15, "Karl");
      AddData(33, "Sacha");
      AddData(24, "Bill");
      AddData(39, "Daniel");
      AddData(14, "Corrado");
      AddData(22, "Marlon");
      AddData(24, "Laurent");

      DataContext = Data;
    }

    public ObservableCollection<LinqDataSample> Data
    {
      get
      {
        return _data;
      }
      set
      {
        _data = value;
      }
    }

    private void AddData(int value, string name)
    {
      _data.Add(new LinqDataSample() { Name = name, Value = value });
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
      int value = 0;
      string name = txtName.Text;
      if (!string.IsNullOrEmpty(name))
      {
        if (int.TryParse(txtValue.Text, out value))
        {
          _data.Add(new LinqDataSample() { Name = name, Value = value });
        }
      }
    }
  }
}

Let’s break this code down. We create an ObservableCollection, which we’d normally fill using LINQ to retrieve data from the database. The DataContext allows the XAML to bind to the collection. In the button click method, we are going to update the observable collection with values that the user enters in on the control (we’d normally update the database at this point too). If you’re not too aware of how Silverlight and WPF works, then the instant update to the chart because of the ObservableCollection is awesome.

<UserControl
  x:Class="GraphingSample.MainPage"
  xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>"
  xmlns:chart="clr-namespace:System.Windows.Controls.DataVisualization.Charting;assembly=System.Windows.Controls.DataVisualization.Toolkit"
  xmlns:d="<a href="http://schemas.microsoft.com/expression/blend/2008">http://schemas.microsoft.com/expression/blend/2008</a>"
  xmlns:mc="<a href="http://schemas.openxmlformats.org/markup-compatibility/2006">http://schemas.openxmlformats.org/markup-compatibility/2006</a>"
  xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a>"
  d:DesignHeight="480"
  d:DesignWidth="640"
  mc:Ignorable="d">
  <Grid x:Name="LayoutRoot">
    <Grid.RowDefinitions>
      <RowDefinition Height="20"/>
      <RowDefinition Height="20"/>
      <RowDefinition Height="20"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="30"/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>
    <TextBlock Grid.Column="0" Grid.Row="0" Text="Name"/>
    <TextBlock Grid.Column="0" Grid.Row="1" Text="Value"/>
    <TextBox x:Name="txtName" Grid.Column="1" Grid.Row="0"/>
    <TextBox x:Name="txtValue" Grid.Column="1" Grid.Row="1"/>
    <Button
      Grid.Column="1"
      Grid.Row="2"
      HorizontalAlignment="Right"
      Click="Button_Click"
      Content="Add"/>
    <chart:Chart Grid.ColumnSpan="2" Grid.Row="3">
      <chart:Chart.Series>
        <chart:PieSeries
          DependentValuePath="Value"
          IndependentValuePath="Name"
          IsSelectionEnabled="True"
          ItemsSource="{Binding}"
          Title="Sample"/>
      </chart:Chart.Series>
    </chart:Chart>
  </Grid>
</UserControl>

The DependentValuePath ties back to the numeric value in the class, and the IndependentValuePath ties up to the name property from our data class. Because we set the ItemsSource to {Binding}, we basically set our item source to pick up the data from the DataContext that we set up in the UserControl.

I will say, at this point, that I normally wouldn’t write my code exactly like this – I’m a big proponent of MVVM, but this is a sample aimed at helping somebody who’s new to Silverlight. Take it from me – this stuff is even cooler with MVVM; if you haven’t explored it yet, you really owe it to yourself.

That’s it – it’s really easy to do, and Silverlight updating means that it’s incredibly good fun. There you go burger87, this one’s for you.

It’s not that hard to add the missing bits to Silverlight.

Recently, my good friend Josh Smith announced that he was putting together a set of MVVM foundation classes. In typical Josh fashion, these classes are hyper useful and hyper clever, and represent some of the great classes he’s produced over the last couple of years to help with MVVM.

Most of these classes work straight out of the box in both WPF and Silverlight, but there is a fly in the ointment. Josh recently developed a class to observe objects that implement INotifyPropertyChanged and it’s seriously good; and it’s virtually totally useless in Silverlight due to Silverlight not supporting the underlying mechanism that is used in the monitoring; the PropertyChangedEventManager class. Now, in a lesser framework than .NET, I’d be worried – but .NET gives us so much freedom to add in the missing functionality, and I wouldn’t be a WPF Disciple if I didn’t like to tinker.

Before I go any further, I will say that there is an alternative implementation in the Silverlight Toolkit in the WeakEventListener. The problem with this class (I use the word problem advisedly here) is that it requires you to use lambda expressions. It also meant that the class that Josh put together would have to be modified, so I decided to see how hard it would be to put together an implementation of PropertyChangedEventManager that works in Silverlight.

As I was working to a well defined feature set (i.e. it only had to work with the functionality in Josh’s class), I didn’t have to recreate the total functionality in the underlying framework classes. I did want it to work with the weak event pattern, however, so without further ado – here’s the functionality in Silverlight.

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Collections.Generic;

namespace System.Windows
{
  /// <summary>
  /// Provides an implementation so that you can use the
  /// "weak event listener" pattern to attach listeners
  /// for the <see cref="PropertyChanged" /> event.
  /// </summary>
  public class PropertyChangedEventManager
  {
    #region Members
    private Dictionary<string, List<WeakReference>> _list;
    private static object SyncLock = new object();
    private static PropertyChangedEventManager _manager = null;
    #endregion

    #region Public methods
    /// <summary>
    /// Adds the specified listener to the list of listeners on the specified source.
    /// </summary>
    ///
<param name="source">The object with the event.</param>
    ///
<param name="listener">The object to add as a listener.</param>
    ///
<param name="propertyName">The name of the property that exists on
    /// source upon which to listen for changes.</param>
    public static void AddListener(INotifyPropertyChanged source,
      IWeakEventListener listener,
      string propertyName)
    {
      Instance.PrivateAddListener(source, listener, propertyName);
    }

    /// <summary>
    /// Removes the specified listener from the list of listeners on the
    /// specified source.
    /// </summary>
    ///
<param name="source">The object with the event.</param>
    ///
<param name="listener">The object to remove as a listener.</param>
    ///
<param name="propertyName">The name of the property that exists
    /// on source upon which to listen for changes.</param>
    public static void RemoveListener(INotifyPropertyChanged source,
      IWeakEventListener listener,
      string propertyName)
    {
      Instance.PrivateRemoveListener(source, listener, propertyName);
    }
    #endregion

    /// <summary>
    /// Get the current instance of <see cref="PropertyChangedEventManager"/>
    /// </summary>
    private static PropertyChangedEventManager Instance
    {
      get
      {
        if (_manager == null)
          _manager = new PropertyChangedEventManager();
        return _manager;
      }
    }

    /// <summary>
    /// Begin listening for the <see cref="PropertyChanged"/> event on
    /// the provided source.
    /// </summary>
    ///
<param name="source">The object on which to start listening
    /// for <see cref="PropertyChanged"/>.</param>
    private void StartListening(INotifyPropertyChanged source)
    {
      source.PropertyChanged += new PropertyChangedEventHandler(this.PropertyChanged);
    }

    /// <summary>
    /// Stop listening for the <see cref="PropertyChanged"/> event on the
    /// provided source.
    /// </summary>
    ///
<param name="source">The object on which to start listening for
    /// <see cref="PropertyChanged"/>.</param>
    private void StopListening(INotifyPropertyChanged source)
    {
      source.PropertyChanged -= new PropertyChangedEventHandler(this.PropertyChanged);
    }

    /// <summary>
    /// The method that handles the <see cref="INotifyPropertyChanged.PropertyChanged"/> event.
    /// </summary>
    ///
<param name="sender">The source of the event.</param>
    ///
<param name="args">A <see cref="PropertyChangedEventArgs"/> that
    /// contains the event data.</param>
    private void PropertyChanged(object sender, PropertyChangedEventArgs args)
    {
      List<WeakReference> list = _list[args.PropertyName];
      if (list != null)
      {
        // We have the listeners. Deal with them
        foreach (WeakReference item in list)
        {
          IWeakEventListener eventItem = item.Target as IWeakEventListener;
          if (eventItem != null && item.IsAlive)
          {
            eventItem.ReceiveWeakEvent(this.GetType(), sender, args);
          }
        }
      }
    }

    /// <summary>
    /// Private method to add the specified listener to the list of listeners
    /// on the specified source.
    /// </summary>
    ///
<param name="source">The object with the event.</param>
    ///
<param name="listener">The object to add as a listener.</param>
    ///
<param name="propertyName">The name of the property that exists
    /// on source upon which to listen for changes.</param>
    private void PrivateAddListener(INotifyPropertyChanged source,
      IWeakEventListener listener,
      string propertyName)
    {
      if (_list == null)
      {
        _list = new Dictionary<string, List<WeakReference>>();
      }

      lock (SyncLock)
      {
        WeakReference reference = new WeakReference(listener);
        if (_list.ContainsKey(propertyName))
        {
          _list[propertyName].Add(reference);
        }
        else
        {
          List<WeakReference> list = new List<WeakReference>();
          list.Add(reference);
          _list.Add(propertyName, list);
        }
        // Now, start listening to source
        StartListening(source);
      }
    }

    /// <summary>
    /// Private method to remove the specified listener from the list of listeners
    /// on the specified source.
    /// </summary>
    ///
<param name="source">The object with the event.</param>
    ///
<param name="listener">The object to remove as a listener.</param>
    ///
<param name="propertyName">The name of the property that exists on
    /// source upon which to listen for changes.</param>
    private void PrivateRemoveListener(INotifyPropertyChanged source,
      IWeakEventListener listener,
      string propertyName)
    {
      if (_list != null)
      {
        lock (SyncLock)
        {
          if (_list.ContainsKey(propertyName))
          {
            // Stop responding to changes
            StopListening(source);
            // Remove the item from the list.
            WeakReference reference = null;
            foreach (WeakReference item in _list[propertyName])
            {
              if (item.Target.Equals(listener))
              {
                reference = item;
              }
            }
            if (reference != null)
            {
              _list[propertyName].Remove(reference);
            }
          }
        }
      }
    }
  }
}

The only thing that’s missing is the weak event listener interface (IWeakEventListener):

using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;

namespace System.Windows
{
  /// <summary>
  /// Provides event listening support for classes that expect to receive events
  /// through the WeakEvent pattern and a WeakEventManager.
  /// </summary>
  public interface IWeakEventListener
  {
    /// <summary>
    /// Receives events from the centralized event manager.
    /// </summary>
    ///
<param name="managerType">The type of the WeakEventManager calling this method.</param>
    ///
<param name="sender">Object that originated the event.</param>
    ///
<param name="e">Event data.</param>
    /// <returns>true if the listener handled the event. It is considered an error by the
    /// WeakEventManager handling in WPF to register a listener for an event that the
    /// listener does not handle. Regardless, the method should return false if it receives
    /// an event that it does not recognize or handle.
    /// </returns>
    bool ReceiveWeakEvent(Type managerType, object sender, EventArgs e);
  }
}

That’s it – that’s all you need to add in to add the “missing” functionality. Simple, isn’t it?

You can download the source here. Note that you’ll have to rename the file from .doc to .zip before you can decompress it.

Silverlight OverrideCursor

One of the really great things you can do with WPF is use Mouse.OverrideCursor to set the cursor for the entire application. This is useful, for instance, if you want your application to perform a lengthy operation, and have the cursor change to a wait cursor, for the duration of the operation. You’d normally do this like:

public void DoAReallyLongOperation()
{
  Cursor savedCursor = Mouse.OverrideCursor;
  try
  {
    PerformMyLengthyOperation();
  }
  finally
  {
    Mouse.OverrideCursor = savedCursor
  }
}

So far, so good. Now, of course, you’re going to run off to your Silverlight applications and do exactly the same for your lengthy operations, aren’t you? After all, Silverlight is a lightweight version of WPF, so surely this will be there for you to use.

Well no. Silverlight doesn’t support the OverrideCursor, but adding it shouldn’t be too hard should it? Well, it turns out that adding the OverrideCursor isn’t as easy as you’d think it would be. If you change the cursor on your page to a wait cursor, for instance, it will still be an IBeam when you move over a text box. This means that your code needs to traverse the visual tree looking for all of the child elements, and setting the cursor to the new cursor.

Edit: Since I posted this earlier today, an edge case was suggested that needed addressing. Basically, the code needs to be able to reset the text boxes back to the IBeam assuming that the OverrideCursor is set back.

The following class provides an attached property that should help greatly with this:

/// <summary>
/// Mouse handling class to simulate the OverrideCursor functionality in WPF.
/// </summary>
public class Mouse : DependencyObject
{
  #region Members
  private static Cursor _oldCursor;
  private static bool _isResetting = false;
  private static Cursor _overrideCursor;
  #endregion
  /// <summary>
  /// Recursively traverse the visual tree, setting the cursor as appropriate.
  /// </summary>
  ///
<param name="current">The element to iterate over.</param>
  ///
<param name="cursor">The cursor to set to.</param>
  /// <remarks>
  /// If the new cursor is the same as the stored original cursor,
  /// then we assume that this is a reset operation taking place.
  /// At this point, we reset the cursor to the original for the element,
  /// irrespective of what the Cursor states.
  /// </remarks>
  internal static void TraverseVisualTree(object current, Cursor cursor)
  {
    DependencyObject ob = current as DependencyObject;
    if (ob != null)
    {
      if (ob is FrameworkElement)
      {
        FrameworkElement element = ob as FrameworkElement;
        Cursor oldCursor = GetOldCursor(element);
        Cursor newCursor = cursor;
        // If this is a reset, then get the old cursor reference
        // back so that we can use this.
        if (_isResetting)
        {
          newCursor = oldCursor;
          SetOldCursor(element, null);
        }
        else
        {
          SetOldCursor(element, element.Cursor);
        }
        element.Cursor = newCursor;
      }
      int counter = VisualTreeHelper.GetChildrenCount(ob);
      for (int i = 0; i < counter; i++)
      {
        object depObj = VisualTreeHelper.GetChild(ob, i);
        TraverseVisualTree(depObj, cursor);
      }
    }
  }
  /// <summary>
  /// The OverrideCursor attached property.
  /// </summary>
  public static readonly DependencyProperty OverrideCursorProperty =
    DependencyProperty.RegisterAttached("OverrideCursor",
    typeof(Cursor),
    typeof(UserControl),
    new PropertyMetadata(null, OnCursorChanged));
  /// <summary>
  /// The OldCursor attached property.
  /// </summary>
  private static readonly DependencyProperty OldCursorProperty =
    DependencyProperty.RegisterAttached("OldCursor",
    typeof(Cursor),
    typeof(UserControl),
    new PropertyMetadata(null));
  /// <summary>
  /// Called when the cursor changes.
  /// </summary>
  private static void OnCursorChanged(DependencyObject source,
    DependencyPropertyChangedEventArgs e)
  {
    if (!(source is FrameworkElement))
      return;
    // If the "old" cursor is the same as the "new" cursor, the
    // code will reset each elements cursor back to its original value.
    _isResetting = (_oldCursor == e.NewValue);
    if (!_isResetting)
    {
      _oldCursor = e.OldValue as Cursor;
    }
    TraverseVisualTree(source, e.NewValue as Cursor);
  }
  /// <summary>
  /// Get the override cursor.
  /// </summary>
  ///
<param name="source">The object to get the override cursor for.</param>
  /// <returns>The populated override cursor.</returns>
  public static Cursor GetOverrideCursor(DependencyObject source)
  {
    return source.GetValue(OverrideCursorProperty) as Cursor;
  }
  /// <summary>
  /// Set the override cursor.
  /// </summary>
  ///
<param name="source">The object to set the cursor for.</param>
  ///
<param name="value">The cursor value to set.</param>
  public static void SetOverrideCursor(DependencyObject source, object value)
  {
    source.SetValue(OverrideCursorProperty, value);
  }
  /// <summary>
  /// Set the old cursor.
  /// </summary>
  ///
<param name="source">The object to set the cursor for.</param>
  ///
<param name="value">The cursor value to set.</param>
  private static void SetOldCursor(DependencyObject source, object value)
  {
    source.SetValue(OldCursorProperty, value);
  }
  /// <summary>
  /// Get the old cursor.
  /// </summary>
  ///
<param name="source">The object to get the old cursor for.</param>
  /// <returns>The populated old cursor.</returns>
  private static Cursor GetOldCursor(DependencyObject source)
  {
    return source.GetValue(OldCursorProperty) as Cursor;
  }
}