Logging display and WPF

October 12, 2009 peteohanlon 3 comments

A question appeared over on the Code Project forums today about binding the output from log4net into WPF. The question asked was:

“I’m trying to use Log4net to log messages within my application. I’m adding a WPF window and want to stream the messages to the window. Log4net provides a TextWriterAppender that takes a StringWriter and writes logged events to the StringWriter, flushing it after each event.I want to simply connect the output of the StringWriter as the Text property on a TextBox. When I started this, it seemed simple and obvious – now I’m less sure. Ideally, I would simply like to bind the StringWriter to the TextBox, but haven’t found the incantation.

The basic problem is that the StringWriter doesn’t provide something like the INotifyPropertyChanged event to trigger code output a new log message (unless there is something behind the scenes I haven’t found).

I’ve see many examples of binding, all of which seem to presume that I have control over the writer itself. Am I missing something simple (I hope), or is this really not that straightforward.”

This is a very good question, so I thought I’d knock together a quick sample application to demonstrate how to do this. The first thing to remember is that log4net allows you to create your own appenders and use them in your application. The second thing to remember is that you need to hook INotifyPropertyChanged into the mechanism. To that end, I created the following appender:

namespace log4netSample.Logging
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using log4net.Appender;
  using System.ComponentModel;
  using System.IO;
  using System.Globalization;
  using log4net;
  using log4net.Core;

  /// <summary>
  /// The appender we are going to bind to for our logging.
  /// </summary>
  public class NotifyAppender : AppenderSkeleton, INotifyPropertyChanged
  {
    #region Members and events
    private static string _notification;
    private event PropertyChangedEventHandler _propertyChanged;

    public event PropertyChangedEventHandler PropertyChanged
    {
      add { _propertyChanged += value; }
      remove { _propertyChanged -= value; }
    }
    #endregion

    /// <summary>
    /// Get or set the notification message.
    /// </summary>
    public string Notification
    {
      get
      {
        return _notification; ;
      }
      set
      {
        if (_notification != value)
        {
          _notification = value;
          OnChange();
        }
      }
    }

    /// <summary>
    /// Raise the change notification.
    /// </summary>
    private void OnChange()
    {
      PropertyChangedEventHandler handler = _propertyChanged;
      if (handler != null)
      {
        handler(this, new PropertyChangedEventArgs(string.Empty));
      }
    }

    /// <summary>
    /// Get a reference to the log instance.
    /// </summary>
    public NotifyAppender Appender
    {
      get
      {
        return Log.Appender;
      }

    }

    /// <summary>
    /// Append the log information to the notification.
    /// </summary>
    /// <param name="loggingEvent">The log event.</param>
    protected override void Append(LoggingEvent loggingEvent)
    {
      StringWriter writer = new StringWriter(CultureInfo.InvariantCulture);
      Layout.Format(writer, loggingEvent);
      Notification += writer.ToString();
    }
  }
}

Whenever a new message is appended, the Notification is updated and the PropertyChangedEventHandler is called to notify the calling application that the binding has been updated. In order to use this appender, you need to hook it into your configuration:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="log4net"
      type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
  </configSections>
  <appSettings>
    <add key="log4net.Internal.Debug" value="false"/>
  </appSettings>
  <system.diagnostics>
    <trace autoflush="true">
      <listeners>
        <add name="textWriterTraceListener"
             type="System.Diagnostics.TextWriterTraceListener"
             initializeData="C:\log4net_internal.log"/>
      </listeners>
    </trace>
  </system.diagnostics>
  <log4net>
    <appender name="NotifyAppender" type="log4netSample.Logging.NotifyAppender" >
      <layout type="log4net.Layout.PatternLayout">
        <param name="Header" value="[Header]\r\n" />
        <param name="Footer" value="[Footer]\r\n" />
        <param name="ConversionPattern" value="%d [%t] %-5p %c %m%n" />
      </layout>
    </appender>

    <root>
      <level value="ALL" />
      <appender-ref ref="NotifyAppender" />
    </root>
  </log4net>
</configuration>

Note that you might want to add the following line into your AssemblyInfo.cs file:

[assembly: log4net.Config.XmlConfigurator(Watch=true)]

I find the following class really helpful when logging:

namespace log4netSample.Logging
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using log4net;
  using log4net.Config;
  using log4net.Appender;
  using log4net.Repository.Hierarchy;

  public enum LogLevel
  {
    Debug = 0,
    Error = 1,
    Fatal = 2,
    Info = 3,
    Warning = 4
  }
  /// <summary>
  /// Write out messages using the logging provider.
  /// </summary>
  public static class Log
  {
    #region Members
    private static readonly ILog _logger = LogManager.GetLogger(typeof(Log));
    private static Dictionary<LogLevel, Action<string>> _actions;
    #endregion

    /// <summary>
    /// Static instance of the log manager.
    /// </summary>
    static Log()
    {
      XmlConfigurator.Configure();
      _actions = new Dictionary<LogLevel, Action<string>>();
      _actions.Add(LogLevel.Debug, WriteDebug);
      _actions.Add(LogLevel.Error, WriteError);
      _actions.Add(LogLevel.Fatal, WriteFatal);
      _actions.Add(LogLevel.Info, WriteInfo);
      _actions.Add(LogLevel.Warning, WriteWarning);
    }

    /// <summary>
    /// Get the <see cref="NotifyAppender"/> log.
    /// </summary>
    /// <returns>The instance of the <see cref="NotifyAppender"/> log, if configured.
    /// Null otherwise.</returns>
    public static NotifyAppender Appender
    {
      get
      {
        foreach (ILog log in LogManager.GetCurrentLoggers())
        {
          foreach (IAppender appender in log.Logger.Repository.GetAppenders())
          {
            if (appender is NotifyAppender)
            {
              return appender as NotifyAppender;
            }
          }
        }
        return null;
      }
    }

    /// <summary>
    /// Write the message to the appropriate log based on the relevant log level.
    /// </summary>
    /// <param name="level">The log level to be used.</param>
    /// <param name="message">The message to be written.</param>
    /// <exception cref="ArgumentNullException">Thrown if the message is empty.</exception>
    public static void Write(LogLevel level, string message)
    {
      if (!string.IsNullOrEmpty(message))
      {
        if (level > LogLevel.Warning || level < LogLevel.Debug)
          throw new ArgumentOutOfRangeException("level");

        // Now call the appropriate log level message.
        _actions[level](message);
      }
    }

    #region Action methods
    private static void WriteDebug(string message)
    {
      if (_logger.IsDebugEnabled)
        _logger.Debug(message);
    }

    private static void WriteError(string message)
    {
      if (_logger.IsErrorEnabled)
        _logger.Error(message);
    }

    private static void WriteFatal(string message)
    {
      if (_logger.IsFatalEnabled)
        _logger.Fatal(message);
    }

    private static void WriteInfo(string message)
    {
      if (_logger.IsInfoEnabled)
        _logger.Info(message);
    }

    private static void WriteWarning(string message)
    {
      if (_logger.IsWarnEnabled)
        _logger.Warn(message);
    }
    #endregion
  }
}

It’s a simple matter then to do something like Log.Write(LogLevel.Info, “This is my message”);

If you download the attached sample, you’ll get to see the whole application running in all its glory, and you can see how updating the log results in the output being updated. Don’t forget to rename the .doc file to .zip when you save it.

log4netsamplezip

Textbox Drag/Drop in WPF

September 28, 2009 peteohanlon Leave a comment

So last week, somebody posted a question on Code Project about why a Drag Drop into a TextBox in WPF doesn’t actually work. When you attempt to drag and drop an item into a TextBox, it refuses to cooperate and leaves the mouse cursor as the Drop denied cursor and you can’t drop into the field. (Incidentally, this behaviour also applies to RichTextBox and FlowDocument controls). The reason that you can’t drop into these fields, even if you set AllowDrop to true, is that these particular controls mark drag and drop events as handled, preventing you from handling them yourself.

Now this might seem like a big problem – it certainly makes it look like you can’t drag/drop into a textbox, and this would seem to be a huge oversight on Microsoft’s part. Fortunately, with a little bit of knowledge of how WPF handles commands, it’s actually fairly easy to come up with a workaround. Remember that I said that WPF marks these operations as handled? This is the key to being able to work around it – each particular event (such as a DragOver event), also has a corresponding Preview event which we can hook into to perform our processing. Before I show you the code though, the OP posted a follow up query:

“A specific question I have about your solution is that you get the standard mouse cursor with the plus sign inside a box when the drag operation enters the edit box. In my initial solution to the drop into a ListBox I got a mouse cursor with an empty box, not the box with the plus sign. By experimenting I determined that you achieve this with the code you have in the PreviewDrag events. What about that code gets you the cursor with the plus sign, avoiding that anemic cursor without the plus sign?”

The following filename drag/drop sample demonstrates how changing the DragDropEffects parameter changes the appearance of the drop cursor, in answer to the Original Posters followup question:

<Window x:Class="SampleDragDrop.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:sys="clr-namespace:System;assembly=mscorlib"
  Title="Window1" Height="274" Width="300">
  <Window.Resources>
    <ObjectDataProvider
        MethodName="GetValues"
        ObjectType="{x:Type sys:Enum}"
        x:Key="DragProvider">
      <ObjectDataProvider.MethodParameters>
        <x:Type TypeName="DragDropEffects" />
      </ObjectDataProvider.MethodParameters>
    </ObjectDataProvider>
    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="Margin" Value="3" />
      <Setter Property="VerticalAlignment" Value="Center" />
    </Style>
  </Window.Resources>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="101*" />
      <ColumnDefinition Width="177*" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="27*" />
      <RowDefinition Height="203.258*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <TextBlock Text="Drag Drop Effects" Grid.Column="0" Grid.Row="0" />
    <TextBlock Text="Drop target" Grid.Column="0" Grid.Row="1" />
    <TextBlock Text="Handled" Grid.Column="0" Grid.Row="2" />
    <ComboBox
      x:Name="cboDropEffects"
      Grid.Row="0"
      Grid.Column="1"
      Margin="2"
      SelectedIndex="0"
      ItemsSource="{Binding Source={StaticResource DragProvider}}" />
    <TextBox
      Grid.Row="1"
      Grid.Column="1"
      Margin="2"
      PreviewDragEnter="TextBox_PreviewDragEnter"
      PreviewDragOver="TextBox_PreviewDragEnter"
      PreviewDrop="TextBox_PreviewDrop" />
    <CheckBox x:Name="chkHandled" IsChecked="True" Grid.Row="2" Grid.Column="1" Margin="2" />
  </Grid>
</Window>

If you look carefully at the code, you see that we bind PreviewDragEnter and the PreviewDragOver to the same event handler. The PreviewDrop event maps to a different event handler, where we actually perform the drop of the filename.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SampleDragDrop
{
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    public Window1()
    {
      InitializeComponent();
    }

    private void TextBox_PreviewDragEnter(object sender, DragEventArgs e)
    {
      e.Effects = (DragDropEffects)cboDropEffects.SelectedItem;
      if (chkHandled.IsChecked.HasValue)
      {
        e.Handled = chkHandled.IsChecked.Value;
      }
    }

    private void TextBox_PreviewDrop(object sender, DragEventArgs e)
    {
      object text = e.Data.GetData(DataFormats.FileDrop);
      TextBox tb = sender as TextBox;
      if (tb != null)
      {
        tb.Text = string.Format("{0}", ((string[])text)[0]);
      }
    }
  }
}

When you run the sample, play around with the Drag Drop Effects values, and setting/unsetting the Handled checkbox, to see what behaviour the textbox exhibits (and the answer to the OPs question, is that setting e.Effects to DragDropEffects.All sets the cursor to the relevant cursor).

This sample is available here: SampleDragDrop. Don’t forget to change the extension from .doc to .zip when you download it.

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.

July 19, 2009 peteohanlon 9 comments

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.

I’m leading a parallel life

June 28, 2009 peteohanlon 5 comments

So, I’ve just started looking at a new .NET language from Microsoft called Axum (available here). At this point you might be tempted, as I originally was, to complain that there’s no need for Microsoft to produce yet another language. After all, we have perfectly servicable languages in C#, VB.NET and (for the linguistically adventurous) F#. Why on earth is Microsoft wasting its time on another language?

Well, it turns out that there’s a very good reason for them to be looking into creating a new one. Axum fits a niche that, while other languages could do what it does, these other languages weren’t originally designed for. Axum is designed for applications that require parallel task exection. As it is designed to create parallel applications, the language offers first class constructs for achieving parallelisation.

The Axum documentation, sparse as it is at the moment, identifies that some tasks are easily amenable to parallelisation because the tasks are independent of each other, and require little synchronisation; other applications have dependencies that require coordination. Axum, as a language, allows us to arrange the coordination between these components in a way that closely matches the way we would conceive of the solutions.

I said, before, that other languages offer us the ability to parallize tasks, so it’s hard to see what Axum brings to the ball, so to speak. Well Axum removes one feature that normally causes problems for developers creating parallel applications if they aren’t careful. It removes the ability for components to share or mutate state from other threads. It provides an isolation model that promotes a disciplined access to shared state, and encourages its use from the start rather than being added as an afterthought.

At this stage, I must stress that Axum is an experimental language, similar enough to C# not to be daunting. This similarity, though, could also cause problems at first glance because it’s so easy to try and do things the C# way, which is not always the Axum way.

Without further ado we’re going to write our first Axum application. It’s a variation of the Hello World described in the Axum Programmers Guide. Assuming you’ve downloaded and installed Axum in either Visual Studio 2008 or Visual Studio 2010, select File > New > Project > Axum > Windows > Console Application. Call the application HelloAxum and click OK. You’ll now get some boilerplate code which you’re going to replace with:

using System;
agent HelloAxum : Microsoft.Axum.ConsoleApplication
{
  override int Run(string[] args)
  {
    Console.WriteLine("Hello Axum");
  }
}

The first thing to note about this application is that it has full access to .NET features, such as the BCL or Console.WriteLine.

Second, we’ve defined our unit of work as an agent rather than a class. An agent is conceptually similar to an actor (in fact Axum is well suited to being mapped out with UML). Agents represent autonomous elements that communicate using messages and so on. Here’s my first problem with Axum; why not call it an actor? Why define a new term here? It just feels a natural fit, for me, to use actor here rather than agent.

Anyway, terminology quibbles aside, agents are very different to developing using OOP. These differences are by design and are there for very good reasons. Agents don’t provide public methods or exhibit state, so you can’t modify fields externally. This means that you can’t call an agent method directly, so you might be tempted to think that methods are useless here. What you can do and what you do, in fact, do, is send a message to the agent and arrange for the agent to get back to you with a response when it is apropriate.

In our sample application we derive from a ConsoleApplication agent which provides the basis for working with console applications.

At this stage, you may be feeling distinctly underwhelmed. After all, we’ve not really done any parallel processing. It’s time to mix things up a bit and do some parallel work. Let’s actually create a couple of agents and pass messages between them. Along the way, we’re going to learn some of the terminology in Axum starting with channels and ports.

Remember that we said that we couldn’t reach into agents? Well, how do we set or get this data? The ability to do this lies in channels – which (in OO terms) defines the interface that our decoupled agents will communicate through. The ports, on a channel, define the inputs and outputs.
In order to define a channel, we use the channel keyword. Here’s a simple channel:

channel HelloAxumChannel
{
  input string Name;
  output string Text;
}

When you use a channel data goes in, cunningly enough, into the inputs and is returned via the outputs. Notice that the channel doesn’t actually tell you how it does it – it only tells you what it does. Now let’s add the implementation.

agent HelloAgent : channel HelloAxumChannel
{
  public HelloAgent()
  {
    string item = receive(PrimaryChannel::Name);

    PrimaryChannel::Text <-- string.Format("Hello {0}", item);
  }
}

This agent waits for a message to arrive on the Name port (the receive statement). Once this is received, it sends a message to the Text port on the PrimaryChannel (the PrimaryChannel is a public property on the channel that gives access to the channel being implemented). It then sends a message to the Created port. Now, received is a blocking operation, meaning that it waits until a message arrives on that port. Now, let’s do something with this – let’s actually “instantiate” this agent and pass a message to it.

public domain Program
{
    agent HelloAxum : Microsoft.Axum.ConsoleApplication
    {
        override int Run(string[] args)
        {
            var proc = HelloAgent.CreateInNewDomain();

            Console.Write("Enter your name:");
            string value = Console.ReadLine();
            proc::Name <-- value;
           
            string outputText = receive(proc::Text);
            Console.WriteLine(outputText);
            Console.ReadKey();
        }

    }
}

In order to instantiate our agent, we use CreateInNewDomain. Once it’s been created we pass messages into it using <–. Again, this process waits for a message from our agent in proc::Text. That’s it – we’ve got a parallel application. (Here it is in all it’s glory):

using System;
using Microsoft.Axum;
using System.Concurrency.Messaging;

namespace AxumApplication1
{
    public domain Program
    {
        agent HelloAxum : Microsoft.Axum.ConsoleApplication
        {
            override int Run(string[] args)
            {
                var proc = HelloAgent.CreateInNewDomain();

                Console.Write("Enter your name:");
                string value = Console.ReadLine();
                proc::Name <-- value;
               
                string outputText = receive(proc::Text);
                Console.WriteLine(outputText);
                Console.ReadKey();
            }

        }
    }
   
    channel HelloAxumChannel
    {
        input string Name;
        output string Text;
    }
   
    agent HelloAgent : channel HelloAxumChannel
    {
        public HelloAgent()
        {
            string item = receive(PrimaryChannel::Name);
           
            PrimaryChannel::Text <-- string.Format("Hello {0}", item);
        }
    }
}

So, do I like Axum? Well, yes I do – I’ve only just begun to scratch the surface of what it can do here; look for more from me in future blogs. I only hope that it actually goes somewhere – I’d hate to see the project die for lack of interest. Obviously, you know my love of WPF, so I’d also like Axum to provide first class WPF integration. I’m watching Axum with interest.

Categories: Axum Tags: ,

Binding Passwords

June 10, 2009 peteohanlon 1 comment

Those who’ve been following my blog and conversations with the WPF Disciples know that I love the databinding power of WPF, and in almost all cases I’m a very happy bunny. There is one stain in the awe inspiring goodness that is bound applications, and that’s the PasswordBox. Superficially, this control looks like a textbox, but there is a problem when you write MVVM applications and rely on binding the way I do; you can’t bind to it. Yes, you heard it right, you can’t bind with a PasswordBox.

There’s a good reason for this lack of binding – PasswordBox.Password is not a Dependency Property, ostensibly because this would result in the password being stored in clear text in memory, which is a potential security concern. If, however, you aren’t too worried about this potential security breach, there is a workround. Good news, folks – the following class (taken from my forthcoming Twitter client Songbird) is a way to perform binding with the PasswordBox.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;

namespace SongBird.Infrastructure
{
    /// <summary>
    /// This class adds binding capabilities to the standard WPF PasswordBox.
    /// </summary>
    public class BoundPasswordBox
    {
        #region BoundPassword
        private static bool _updating = false;

        /// <summary>
        /// BoundPassword Attached Dependency Property
        /// </summary>
        public static readonly DependencyProperty BoundPasswordProperty =
            DependencyProperty.RegisterAttached("BoundPassword",
                typeof(string),
                typeof(BoundPasswordBox),
                new FrameworkPropertyMetadata(string.Empty, OnBoundPasswordChanged));

        /// <summary>
        /// Gets the BoundPassword property.
        /// </summary>
        public static string GetBoundPassword(DependencyObject d)
        {
            return (string)d.GetValue(BoundPasswordProperty);
        }

        /// <summary>
        /// Sets the BoundPassword property.
        /// </summary>
        public static void SetBoundPassword(DependencyObject d, string value)
        {
            d.SetValue(BoundPasswordProperty, value);
        }

        /// <summary>
        /// Handles changes to the BoundPassword property.
        /// </summary>
        private static void OnBoundPasswordChanged(
            DependencyObject d,
            DependencyPropertyChangedEventArgs e)
        {
            PasswordBox password = d as PasswordBox;
            if (password != null)
            {
                // Disconnect the handler while we're updating.
                password.PasswordChanged -= PasswordChanged;
            }

            if (e.NewValue != null)
            {
                if (!_updating)
                {
                    password.Password = e.NewValue.ToString();
                }
            }
            else
            {
                password.Password = string.Empty;
            }
            // Now, reconnect the handler.
            password.PasswordChanged += new RoutedEventHandler(PasswordChanged);
        }

        /// <summary>
        /// Handles the password change event.
        /// </summary>
        static void PasswordChanged(object sender, RoutedEventArgs e)
        {
            PasswordBox password = sender as PasswordBox;
            _updating = true;
            SetBoundPassword(password, password.Password);
            _updating = false;
        }

        #endregion

    }
}

Using it couldn’t be simpler, just add a reference to the namespace in your XAML, and update your PasswordBox with the BoundPasswordBox class. You’ve now got a bindable PasswordBox.

<PasswordBox
    Grid.Column="1"
    Grid.Row="2"
    Margin="5,5,5,5"
    password:BoundPasswordBox.BoundPassword="{Binding Path=Password,
        Mode=TwoWay,
        UpdateSourceTrigger=PropertyChanged}"
    VerticalAlignment="Center"/>

Please select your collection

May 21, 2009 peteohanlon 10 comments

In this post, I’d like to cover a fairly common scenario that I’ve received various bits of email about as WPF is becoming more and more popular with developers. A common requirement for a lot of developers is to have a ComboBox contain an entry at the top of the list prompting the user to select an item from the list. As the list is normally populated using a collection of some description it would seem, at first glance, that the only way to actually put a selection choice in is to actually modify the list somehow – and this is precisely the advice that several “professional developers” offer.

You can probably guess by the tone of the end of that previous paragraph that I don’t agree with this approach. It just smacks way too much of a hack to my liking. Rejoice though, WPF provides a neat way to get round this problem, and I’m going to demonstrate a limitation of one of the classes we use to get round the limitation.

Right, let’s start off by defining the class that we are going to display in the ComboBox. It’s a variation of our old faithful, the Person class.

namespace CompositeTest
{
  using System;
  using System.ComponentModel;

  /// <summary>
  /// This class defines the person.
  /// </summary>
  public class Person : INotifyPropertyChanged
  {
    private string _name;
    /// <summary>
    /// The name of the person.
    /// </summary>
    public string Name
    {
      get
      {
        return _name;
      }
      set
      {
        if (_name != value)
        {
          _name = value;
          OnChange("Name");
        }
      }
    }

    /// <summary>
    /// Raise change notifications.
    /// </summary>
    ///
<param name="property">The property to raise the
    /// notification on.</param>
    protected virtual void OnChange(string property)
    {
      PropertyChangedEventHandler handler = propertyChanged;
      if (handler != null)
      {
        handler(null, new PropertyChangedEventArgs(property));
      }
    }
    #region INotifyPropertyChanged Members

    private event PropertyChangedEventHandler propertyChanged;
    public event PropertyChangedEventHandler PropertyChanged
    {
      add { propertyChanged += value; }
      remove { propertyChanged -= value; }
    }

    #endregion
  }
}

As you can see, it’s a bog-standard POCO implementation, with no “goo” in place to handle a “magic” item.

Next, we define the XAML that we are going to use. Don’t worry about the complexity at the moment, as we’ll soon break it down to better understand what’s going on.

<Window x:Class="CompositeTest.Window1"
  xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>"
  xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a>"
  Title="Selection Sample" Height="200" Width="300"
  xmlns:dt="clr-namespace:CompositeTest"
  x:Name="Window">
  <Window.Resources>
    <DataTemplate x:Key="PersonTemplate">
      <StackPanel>
        <TextBlock Text="{Binding Path=Name}" />
      </StackPanel>
    </DataTemplate>
    <ControlTemplate x:Key="ValidationTemplate">
      <DockPanel>
        <AdornedElementPlaceholder />
        <TextBlock Foreground="Red"
               FontSize="20"
               ToolTip="You must choose an item">*</TextBlock>
      </DockPanel>
    </ControlTemplate>
  </Window.Resources>
  <StackPanel>
    <ComboBox
      IsEditable="False"
      SelectedIndex="0"
      Margin="20"
      ItemTemplate="{StaticResource PersonTemplate}"
      Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
      >
      <ComboBox.SelectedItem>
        <Binding Path="SelectedPerson"
             ElementName="Window"
             Mode="OneWayToSource">
          <Binding.ValidationRules>
            <dt:PersonValidation />
          </Binding.ValidationRules>
        </Binding>
      </ComboBox.SelectedItem>
      <ComboBox.ItemsSource>
        <CompositeCollection>
          <ComboBoxItem>Please select...</ComboBoxItem>
          <CollectionContainer
            x:Name="peopleCollection"
            x:FieldModifier="private"/>
        </CompositeCollection>
      </ComboBox.ItemsSource>
    </ComboBox>
  </StackPanel>
</Window>

Obviously we want to put something in place to inform the user that they need to select a person from the list. A good way to do this is to put a validation rule into place, and that’s what we are going to do. Here’s the code:

namespace CompositeTest
{
  using System;
  using System.Windows.Controls;
  using System.Globalization;
  /// <summary>
  /// Validate the ComboBox to see whether or not the
  /// user has chosen a person.
  /// </summary>
  public class PersonValidation : ValidationRule
  {
    /// <summary>
    /// Validate the item to see if it's a ComboBoxItem or not.
    /// If it is a ComboBoxItem, this means that the user has
    /// chosen the please select item.
    /// </summary>
    /// <returns>A ValidationResult based on the test</returns>
    public override ValidationResult Validate(object value,
      CultureInfo cultureInfo)
    {
      if (value is ComboBoxItem)
        return new ValidationResult(false,
          "Selection is invalid");
      return new ValidationResult(true, null);
    }
  }
}

The validation logic is fairly simple. If the value is a ComboBoxItem, this means the user has chosen the Please select… option from the list. Any other selection means the user has chosen a Person from the list.

Now, let’s break the XAML down a little bit.

  <Window.Resources>
    <DataTemplate x:Key="PersonTemplate">
      <StackPanel>
        <TextBlock Text="{Binding Path=Name}" />
      </StackPanel>
    </DataTemplate>
    <ControlTemplate x:Key="ValidationTemplate">
      <DockPanel>
        <AdornedElementPlaceholder />
        <TextBlock Foreground="Red"
               FontSize="20"
               ToolTip="You must choose an item">*</TextBlock>
      </DockPanel>
    </ControlTemplate>
  </Window.Resources>

Here we’ve created a data template that we are going to apply to the combo box, and a control template that will be applied when there are validation failures. The use of AdornedElementPlaceHolder is an easy way to place the a decorated control relative to other items in your template.

    <ComboBox
      IsEditable="False"
      SelectedIndex="0"
      Margin="20"
      ItemTemplate="{StaticResource PersonTemplate}"
      Validation.ErrorTemplate="{StaticResource ValidationTemplate}"
      >

Here we’re hooking the item template to the data template, and the error template to the control template we talked about above.

      <ComboBox.SelectedItem>
        <Binding Path="SelectedPerson"
             ElementName="Window"
             Mode="OneWayToSource">
          <Binding.ValidationRules>
            <dt:PersonValidation />
          </Binding.ValidationRules>
        </Binding>
      </ComboBox.SelectedItem>

Whenever the selected item changes, the application is going to perform the validation that we defined in the PersonValidation class. If there’s a failure, the application will apply the validation template. Please note the ElementName element – I’ve defined this as a named attribute in the Window declaration.

      <ComboBox.ItemsSource>
        <CompositeCollection>
          <ComboBoxItem>Please select...</ComboBoxItem>
          <CollectionContainer
            x:Name="peopleCollection"
            x:FieldModifier="private"/>
        </CompositeCollection>
      </ComboBox.ItemsSource>
    </ComboBox>

We finally get to the magic. Where you may be tempted, in normal use, to just set the ItemsSource to a standard Binding, we need to use a CompositeCollection instead. This handy class allows us to put pretty much any type of data into the ItemsSource (within reason). To use it, we add a ComboBoxItem to the CompositeCollection that displays the text we want to appear at the top of the combo box.

Next, we add a collection to the CompositeCollection using a CollectionContainer. In most of the samples you see of this on the web, it binds to a StaticResource and is perfectly happy. If you want to bind to a DataContext, however, you’re kind of stuffed – the CompositeCollection is not Freezable and, in order to bind to the data context, you have to have a chain of Freezable items. So, if you can’t do <CollectionContainer Collection=”{Binding}” /> in your XAML, what can you do?

Well, the answer is to do it in the code behind. All you need to do is set the Collection as in the following class (you need to expose the CollectionContainer to your code behind, hence the use of x:Name on it):

namespace CompositeTest
{
  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Navigation;
  using System.Windows.Shapes;
  using System.Collections.Specialized;
  /// <summary>
  /// Interaction logic for Window1.xaml
  /// </summary>
  public partial class Window1 : Window
  {
    private List<Person> list = new List<Person>();
    public Window1()
    {
      InitializeComponent();

      BindData();
    }
    public object SelectedPerson { get; set; }
    private void BindData()
    {
      list.Add(new Person { Name = "Peter" });
      list.Add(new Person { Name = "Karl" });
      list.Add(new Person { Name = "Sacha" });
      list.Add(new Person { Name = "Bill" });
      list.Add(new Person { Name = "Josh" });

      peopleCollection.Collection = list;
    }
  }
}

Armed with this information, you can now provide Please select functionality in your applications without any real problems now.

Happy coding.

Download: WpfApplication1.zip.

When you download the source, you’ll need to remove the .doc extension.

Easy help with WPF

May 1, 2009 peteohanlon 29 comments

If, like me, you like your applications to provide Context sensitive help, you’ve probably had a play around with the ApplicationCommands.Help command. In order to simplify hooking your help into your application, I’ve written the following code.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Input;
using form = System.Windows.Forms;
using System.Windows.Media;

namespace HelpProvider
{
  /// <summary>
  /// This class provides the ability to easily attach Help functionality
  /// to Framework elements. To use it, you need to
  /// add a reference to the HelpProvider in your XAML. The FilenameProperty
  /// is used to specify the name of the helpfile, and the KeywordProperty specifies
  /// the keyword to be used with the search.
  /// </summary>
  /// <remarks>
  /// The FilenameProperty can be at a higher level of the visual tree than
  /// the KeywordProperty, so you don't need to set the filename each time.
  /// </remarks>
  public static class Help
  {
    /// <summary>
    /// Initialize a new instance of <see cref="Help"/>.
    /// </summary>
    static Help()
    {
      // Rather than having to manually associate the Help command, let's take care
      // of this here.
      CommandManager.RegisterClassCommandBinding(typeof(FrameworkElement),
        new CommandBinding(ApplicationCommands.Help,
          new ExecutedRoutedEventHandler(Executed),
          new CanExecuteRoutedEventHandler(CanExecute)));
    }

    #region Filename

    /// <summary>
    /// Filename Attached Dependency Property
    /// </summary>
    public static readonly DependencyProperty FilenameProperty =
      DependencyProperty.RegisterAttached("Filename", typeof(string), typeof(Help));

    /// <summary>
    /// Gets the Filename property.
    /// </summary>
    public static string GetFilename(DependencyObject d)
    {
      return (string)d.GetValue(FilenameProperty);
    }

    /// <summary>
    /// Sets the Filename property.
    /// </summary>
    public static void SetFilename(DependencyObject d, string value)
    {
      d.SetValue(FilenameProperty, value);
    }

    #endregion
   
    #region Keyword

    /// <summary>
    /// Keyword Attached Dependency Property
    /// </summary>
    public static readonly DependencyProperty KeywordProperty =
      DependencyProperty.RegisterAttached("Keyword", typeof(string), typeof(Help));

    /// <summary>
    /// Gets the Keyword property.
    /// </summary>
    public static string GetKeyword(DependencyObject d)
    {
      return (string)d.GetValue(KeywordProperty);
    }

    /// <summary>
    /// Sets the Keyword property.
    /// </summary>
    public static void SetKeyword(DependencyObject d, string value)
    {
      d.SetValue(KeywordProperty, value);
    }
    #endregion

    #region Helpers
    private static void CanExecute(object sender, CanExecuteRoutedEventArgs args)
    {
      FrameworkElement el = sender as FrameworkElement;
      if (el != null)
      {
        string fileName = FindFilename(el);
        if (!string.IsNullOrEmpty(fileName))
          args.CanExecute = true;
      }
    }

    private static void Executed(object sender, ExecutedRoutedEventArgs args)
    {
      // Call ShowHelp.
      DependencyObject parent = args.OriginalSource as DependencyObject;
      string keyword = GetKeyword(parent);
      if (!string.IsNullOrEmpty(keyword))
      {
        form.Help.ShowHelp(null, FindFilename(parent), keyword);
      }
      else
      {
        form.Help.ShowHelp(null, FindFilename(parent));
      }
    }

    private static string FindFilename(DependencyObject sender)
    {
      if (sender != null)
      {
        string fileName = GetFilename(sender);
        if (!string.IsNullOrEmpty(fileName))
          return fileName;
        return FindFilename(VisualTreeHelper.GetParent(sender));
      }
      return null;
    }
    #endregion

  }
}

Using it couldn’t be simpler, set up the Filename in your XAML and add any keywords you need to search on against your FrameworkElement items. The advantage of this approach is that you can bind different parts of your UI to different helpfiles if you want.

<Window
  x:Class="HelpSample.Window1"
  xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation">http://schemas.microsoft.com/winfx/2006/xaml/presentation</a>"
  xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml">http://schemas.microsoft.com/winfx/2006/xaml</a>"
  Title="Window1" Height="300" Width="300"
  xmlns:help="clr-namespace:HelpProvider;assembly=HelpProvider"
  help:Help.Filename="MyHelpfile.chm"
  >
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>
    <TextBox help:Help.Keyword="MyKeyword" Grid.Row="0" Text="Keyword based search" />
    <TextBox Grid.Row="1" Text="No keyword" />
  </Grid>
</Window>

I hope this helps you as much, as it helps me.

Silverlight OverrideCursor

April 15, 2009 peteohanlon Leave a comment

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;
  }
}

WPF on tour

For those who wonder how committed Microsofties are to giving out the good news about technologies like WPF or Silverlight, prepare to be amazed. My fellow disciples, and commited Microsofters, the awesome Mr Karl Shifflett and the amazing Jaime Rodriguez are going on tour. That’s right – coming to a country near you (hopefully), is the WPF LOB tour. If you want to know how you can use WPF the right way to create LOB applications, then you owe it to yourself to get yourself out to one of these events.

More info is available here.