Input Localization in Silverlight without IValueConverter

 

The Problem

There are plenty of articles on the web detailing how to localize strings within Silverlight applications, however, one area of confusion seems to be how to get Silverlight to accept text input using the users current culture settings.

For example, if I type 10,1 in a locale that uses the ‘,’ symbol as the decimal symbol I might expect to get the decimal number “10.1” (UK Format), however, I will in fact receive the number 101.

Many examples demonstrate using custom IValueConverter implementations that format and parse values using the current culture to work around this issue , however, this method is tedious, error prone, and unnecessary.

Solution

By default, bindings in Silverlight that do not specify a custom ValueConverter parse input text using the culture specified by the target elements Language property. The Language property is of type XmlLanguage and is one of the few built in inherited properties supported in Silverlight. This means that setting the Language property of the RootVisual will cause all text to be parsed using the users current culture.

One thing to keep in mind is that by default Popup (and descendents such as ChildWindow) do not belong to the root visual tree and will therefore need to be configured independently (or added to the visual tree).

Below is a simple class that returns an XmlLanguage object for the current culture

   1: public class CultureSettings
   2: {
   3:   public XmlLanguage Language
   4:   {
   5:      get
   6:      {
   7:         return XmlLanguage.GetLanguage(Thread.CurrentThread.CurrentCulture.Name);
   8:      }
   9:   }
  10: }

The class is added to the Applications resources

   1: <Application.Resources>
   2:     <ResourceDictionary>
   3:         <Windows:CultureSettings x:Key="CultureSettings"/>
   4:     </ResourcesourceDictionary>
   5: </Application.Resources>
   6:  

And finally bound to the Language property of the root visual

   1: <ContentPresenter x:Name="RootVisual" Language="{Binding Language, Source={StaticResource CultureSettings}}"/>
iMeta Agility Beta is Live!!!

I’m pleased to announce that iMeta Agility Beta is now live!!! iMeta Agility is an entry level tool for managing Agile projects written in Silverlight. Check it out at http://www.imeta.co.uk/Consultancy/Agility.aspx 

All feedback welcome :)

Perhaps now I’ll have more time to Blog about our adventures in Silverlight

MSTest and Silverlight

One thing missing from the Microsoft Silverlight testing framework is Visual Studio integration. Because of this many people end up using the standard non-Silverlight MSTest framework to test their Silverlight code. At first this may sound a little balmy, however, Silverlight assemblies are byte code compatible with normal .NET assemblies and will quite happily run within CLR 2.0. There are a few things, however, you should be aware of:

  1. You can only make calls to APIs that do not require the underlying Silverlight core (agcore), so anything inheriting from DependencyObject is out, as is WCF.
  2. The [SecurityCritical] attribute is ignored, meaning that calls that would normally be prohibited within Silverlight can be made without resulting in a MethodAccessException.

The limitations described in point one may at first seem quite significant, however, if you are abstracting your UI logic using some flavour of MVVM, MVC, MVP, etc. you will more than likely find that your code does not fall into this category, and WCF calls in most cases should be mocked.

The advantage of running your tests within Visual Studio is that you do not need to run all of your tests for each test run, which is particularly useful if you are following a TDD approach. The downside of course is that you have to be confident that running your tests within this environment does not affect the outcome of your tests, its a trade off.

Creating the Test Project

In Visual Studio create a normal (non-Silverlight) test project.

image

(At iMeta we use the “Hybrid” prefix to indicate we are mixing Silverlight and .Net code).

Remove all references from the project except for the reference to Microsoft.VisualStudio.QualityTools.UnitTestFramework

image

Re-add any required references but this time selecting Silverlight assemblies, usually located within “C:\Program Files\Reference Assemblies\Microsoft\Framework\Silverlight\v3.0” and “C:\Program Files\Microsoft SDKs\Silverlight\v3.0\Libraries

Drag-and-Drop MVVM

Ok, by now you’ll probably have realized I’ve been doing quite a bit with drag-and-drop recently. You can find my previous posts here and here. One question you may be asking, particularly if you using Microsoft Prism for Silverlight is how does drag-and-drop fit within MVVM, etc.?

When implementing MVVM (please don’t get tied up too much on MVVM, the same principles will apply to other UI composition patterns) our primary goal is to pull as much code out of the UI as possible easing our ability to test the presentation logic. Now, drag-and-drop is intrinsically a UI feature, so we can’t get away from the UI entirely, but we want the UI to have as little responsibility as possible.

When a drag operation is initiated the data for the operation is set to an IDragViewModel instance, the IDragViewModel represents the presentation data and logic used by the IDragView (which in our case is a drag cursor).

public interface IDragViewModel
{
/// <summary>
/// Gets the source object being dragged.
/// </summary>
object Source { get; }

/// <summary>
/// Gets or sets a value that indicates the effects.
/// </summary>
DragDropEffects Effects
{
get;
set;
}

/// <summary>
/// Gets or sets a value that describes the state of the drag drop operation
/// </summary>
string Description
{
get;
set;
}
}

// create IDragViewModel implementation
var dragModel = new DragViewModel(source);
// initialize drag drop operation
DragDrop.DoDragDrop(fromArgs, null, dragModel, CreateDragView(dragModel),

DragDropEffects.All);


(In our implementation the code that initiates the drag is abstracted away from the UI into a service which is injected into the view).

When the view receives a drag-and-drop related event it translates it into an event which deals purely with view models, removing any references to UI specifics and forwards it to its presenter/view model.

public class DragViewModelEventArgs : EventArgs
{
private readonly IDragViewModel _model;
private readonly object _target;



public DragViewModelEventArgs(object target, IDragViewModel model)
{
_model = model;
_target = target;
}

public object Target
{
get { return _target; }
}

public IDragViewModel Model
{
get { return _model; }
}
}


private void OnDragOver(object sender, DragEventArgs e)
{
var dragModel = e.Data as IDragViewModel;
if (dragModel != null)
{
// extract target
var target = ExtractDropTarget(sender);
if (target != null)
{
// notify ViewModel/Presenter
Model.DragOver(new DragViewModelEventArgs(target, model));
// update drag drop effects from the update model
e.Effects = e.AllowedEffects & dragModel.Effects;
// handled
e.Handled = true;
}
}
}

Below is a simple example of what the DragOver implementation may look like…

public void DragOver(DragViewModelEventArgs args)
{
var source = args.Model.Source as PersonViewModel;
var target = args.Target as PersonViewModel;
if (target != null && source != null && source != target)
{
args.Model.Description = string.Format(CultureInfo.InvariantCulture,
"Insert person '{0}' before person '{1}'", source.FirstName, target.FirstName);
args.Model.Effects = DragDropEffects.Move;
}
else
{
args.Model.Description = string.Empty;
args.Model.Effects = DragDropEffects.None;
}
}

The thing to note is that the behaviour is now in the correct place, does not rely on any UI implementation and is easily testable.

DataGrid Drag-And-Drop

Following on from previous blog on drag-and-drop I thought I’d share my experiences of dragging and dropping rows in a DataGrid. I’ll present two solutions, one for Silverlight 2, and a much simplified version in Silverlight 3. Source code can be found here.

Silverlight 2 Solution

The first problem you will encounter in Silverlight 2 is determining how/when to initiate the drag operation. The most obvious route is to attach to the MouseLeftButtonDown event of the DataGridRow during the DataGrid.LoadingRow event, unfortunately the MouseLeftButtonDown event never fires! (Bear in mind the mouse must be down for us to capture the mouse in our drag operation).

One solution to this is to redefine the template for the DataGridCell and add a MouseLeftButtonDown handler on the appropriate element.

<Style TargetType="local:DataGridCell">   
<!-- Setters Section Omitted For Readability... -->
<ControlTemplate TargetType="local:DataGridCell">
<Grid Name="Root" Background="{TemplateBinding Background}"
MouseLeftButtonDown="OnCellMouseLeftButtonDown">

Or, alternatively, by dynamically attaching a handler at run time during DataGrid.Loaded event.

var realSender = (DependencyObject)sender;
foreach (var element in VisualSearch.FindAll<DataGridCell>(realSender, VisualSearchOptions.MatchDepth))
{
var content = VisualSearch.FindName(element, "Root");
if (content != null)
content.MouseLeftButtonDown += (s, e) => BeginDrag((FrameworkElement)s, e);
}

(VisualSearch is a utility class I have written that performs a breadth first search of the visual tree).

This appears to work quite well, however, you will notice that if the data grid doesn’t have focus when you try to drag a row the MouseLeftButtonDown event still gets swallowed. Now I’ve tried to insert handlers at various points in the visual tree, but try as I might I have not found any element I can reliably attach to that will give me a MouseLeftButtonDown when the grid is receiving focus through a mouse click. So how do we work around this?

Well we know that we will receive a GotFocus event when the grid is focused, if we could determine if the mouse was down when the grid received focus maybe this could help? (Bear with me…) Again, we hit a snag, Silverlight doesn’t provide any direct means to arbitrarily determine the current state of the mouse. But we can use a little trick I’ve discovered during my drag-and-drop adventures, you can only capture the mouse if the primary mouse button is down.

private bool IsMouseDown
{
get
{
if (CaptureMouse())
{
ReleaseMouseCapture();
return true;
}
return false;
}
}

Ok, so now we can determine when we get focus, and whether the mouse is down, how does this help? Well, if we set a flag during the GotFocus event we can then listen for MouseMove events on the DataGridRow (fortunately these are not swallowed) and initiate our drag from there if the flag is set.

_dataGrid.GotFocus += (s, e) =>
{
if (IsMouseDown)
_dragOnMouseMove = true;

};
_dataGrid.LostFocus += (s, e) => _dragOnMouseMove = false;
_dataGrid.MouseMove += (s, e) => _dragOnMouseMove = false;

private void LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.MouseMove += (s, arg) =>
{
if (_dragOnMouseMove && IsMouseDown)
BeginDrag(e.Row);
_dragOnMouseMove = false;
};
}

We clear our flag if we detect a mouse move on the grid to ensure dragging from empty space into a row doesn’t initiate a drag. In combination with our previous MouseLeftButtonDown hook we now have a reliable mechanism for dragging row!!! Phew, that was hard, lets now see how easy it is in Silverlight 3.

Silverlight 3 Solution

Silverlight 3 adds one new feature, specifically (I think) for these types of problems that makes our life a lot more easy.

public void UIElement.AddHandler(RoutedEvent routedEvent, Delegate handler, bool handledEventsToo)

The important parameter is handledEventsToo, this parameter basically informs the element that you want to receive routed events regardless of whether the event has been marked as handled. Armed with this new API our code simply becomes.

private void LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.AddHandler(MouseLeftButtonDownEvent,
new MouseButtonEventHandler((s1, e2) => BeginDrag((FrameworkElement)s1, e2), true);

Drag And Drop In Silverlight

Unfortunately Silverlight does not include any direct API support for drag and drop like WPF. In some respects this is not a bad thing as Silverlight does provide all of the building blocks required to perform drag and drop without leading you down any particular implementation, however, sometimes you just want to get going quickly using something that feels familiar.

To that end I’ve been working on a drag drop framework that is largely compatibility with the WPF implementation, I'll attempt to explain the different parts of the implementation and how they fit together in this blog. For the impatient the source code is available here with samples :).

One thing to keep in mind is that the snippets posted in the blog have generally been simplified to get the point across, you will need to refer to the source for the full implementation.

Tracking the Mouse

To track the mouse during a drag operation you need to capture the mouse by calling UIElement.CaptureMouse. Capturing the mouse ensures that all mouse events are sent to an element regardless of whether the mouse is within the elements bounds. The documentation for CaptureMouse states that the mouse may only be captured if the primary mouse button is down, therefore, all drag operations will need to be initiated from a MouseLeftButtonDown event handler, but this is probably what we want, right?

In keeping with our theme of WPF compatibility the API will need to look something like this:

private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
DragDrop.DoDragDrop(dragSource, data, DragDropEffects.Copy);
}

Which UIElement should our implementation of DragDrop use to track the mouse? Many examples of drag and drop use Application.Current.RootVisual to track the mouse and this would probably work just fine, however, previous work I had done on creating a resizable child window led me away from this solution (Don’t worry, I’ll be blogging about the resizable window soon). We really want an element which can be used as an accurate reference point that we have complete control over, and that is unlikely to be affected by layout changes, etc. Popup to the rescue!!

var mouseTracker = new Popup();
if (!mouseTracker.CaptureMouse())
return false;

mouseTracker.MouseMove += MouseMove;
mouseTracker.MouseLeftButtonUp += MouseLeftButtonUp;
mouseTracker.LostMouseCapture += LostMouseCapture;

Dragging Over

At this point we have managed to initiate a drag operation and we are receiving mouse events though the Popup control, but how do we determine which elements we are dragging over and allow them to participate in the drag operation?

To determine the elements currently under the mouse we can use VisualTreeHelper.FindElementsInHostCoordinates, this method returns an IEnumerable<UIElement> containing all of the elements that contain a specified Point in front to back z-order.

Unfortunately allowing the element to participate in the drag operation is slightly more tricky :( First we define an interface for handling drag drop related events (bear with me, I know what you’re thinking…)

public interface IDropTarget
{
void DragLeave(DragEventArgs e);
void DragEnter(DragEventArgs e);
void DragOver(DragEventArgs e);
void Drop(DragEventArgs e);
object Target
{
get;
}
}

Yes, it would be a bit of a pain if we had to inherit from every control we wanted to support drop events and implement IDropTarget. To overcome this we use another common pattern, the attached behaviour. An attached behaviour is an object that attaches itself (usually via an attached property) to an element and adds some new behaviour to that element.

The implementation of DragDropBehaviour uses an attached property to store an instance of itself against an element.

private static readonly DependencyProperty DragDropBehaviourProperty = 
DependencyProperty.RegisterAttached("DragDropBehaviour", typeof(DragDropBehaviour),
typeof(DragDropBehaviour), new PropertyMetadata(null));

It exposes public GetBehaviour and private SetBehaviour static methods for accessing the value of this property. It also exposes a GetOrCreateBehaviour which can be used when a behaviour instance is required.
public static DragDropBehaviour GetOrCreateBehaviour(DependencyObject target)
{
var behaviour = GetBehaviour(target);
if (behaviour == null)
{
behaviour = new DragDropBehaviour(target);
SetBehaviour(target, behaviour);
}
return behaviour;
}

The behaviour implements the IDropTarget interface delegates calls to events declared on the behaviour.

public event DragEventHandler Drop;
public event DragEventHandler DragOver;
public event DragEventHandler DragEnter;
public event DragEventHandler DragLeave;

Ok, this is all very nice but how does it help? Well if we go back to WPF we will notice that the DragDrop class defines several methods for adding and removing drag drop event handlers.

public static void AddDragOverHandler(DependencyObject element, DragEventHandler handler)
public static void AddDragEnterHandler(DependencyObject element, DragEventHandler handler)
public static void AddDragLeaveHandler(DependencyObject element, DragEventHandler handler)
public static void AddDropHandler(DependencyObject element, DragEventHandler handler)
public static void RemoveDragOverHandler(DependencyObject element, DragEventHandler handler)
public static void RemoveDragEnterHandler(DependencyObject element, DragEventHandler handler)
public static void RemoveDragLeaveHandler(DependencyObject element, DragEventHandler handler)
public static void RemoveDropHandler(DependencyObject element, DragEventHandler handler)

With our attached behaviour in place it is a now a simple task to support these methods.

public static void AddDragOverHandler(DependencyObject element, DragEventHandler handler)
{
if (handler != null)
DragDropBehaviour.GetOrCreateAdapter(element).DragOver += handler;
}

Supporting the AllowDrop property

In WPF an element will only receive drag drop related events if its AllowDrop property is set to true. In WPF the AllowDrop property is inherited meaning that child elements that do not explicitly set this property will inherit the value from their parent. Unfortunately Silverlight does not support inherited properties :(

To overcome this limitation and keep code compatibility with WPF we are going to need some trickery. First we define an enum with the values True, False and Inherited, instead of a bool to represent our AllowDrop value.

public enum AllowDrop { Inherited, False, True}
 
We then define an attached dependency property called AllowDrop (surprisingly) whose type is our enum type and set the default value to Parent indicating the value is inherited by default.
 
public static readonly DependencyProperty AllowDropProperty = 
DependencyProperty.RegisterAttached("AllowDrop", typeof (AllowDrop),
typeof (DragDrop), new PropertyMetadata(AllowDrop.Parent));
We then define a utility method that can return the “real” value of the AllowDrop property taking into account inheritance.
 

private static bool AllowsDrop(DependencyObject element)
{
while (element != null)
{
var result = GetAllowDrop(element);
if (result != AllowDrop.Inherited)
{
return result == AllowDrop.True;
}
element = VisualTreeHelper.GetParent(element);
}
return false;
}


Putting it all together

 
Ok, so we now have the ability to track the mouse, determine which elements we are dragging over and query them to determine if we should forward drag drop related events, the only thing left to mention is the mechanism used to publish those events.
 
As most of you will be aware there is no direct support for declaring your own routed events in Silverlight, however, in our case this is not too much of an issue.
private void BubbleDragEvent(DragEventArgs args, Action<IDropTarget, DragEventArgs> handler)
{
var source = _currentDropTarget;
while (source != null && GetAllowDrop(source) != AllowDrop.False)
{
var dropTarget = source.GetDropTarget();
if (dropTarget != null)
{
handler(dropTarget, args);
if (args.Handled)
return;
}
source = VisualTreeHelper.GetParent(source) as UIElement;
}
}


private void OnDrop()
{
BubbleDragEvent((x, y) => x.Drop(y));
}

 

Conclusion

There is a lot more to the framework like Drag Cursors, Cancellation, etc. but I don’t want to bore you too much…, hopefully you’ve got a feel for how things work and the source code should give you the rest. You will notice that the implementation of DragDrop.DoDragDrop has additional parameters not present in WPF, I’m working on removing these by providing support for a default drag cursors and the option to explicitly set the drag cursor for an element with an attached property. Another thing some of you will notice is the lack of tests, within the project I am running we generally follow a TDD approach. This has proved quite difficult for drag drop,  I’m currently looking at using http://www.artoftest.com WebAii to help me here, I’ll keep you posted on how I get on.

IoC and the Dependency Inversion Principle (DIP)

 

A couple of weeks a go a colleague of mine who was in the first week of a new project asked me "Which inversion of control (IoC) framework should I use?", to which I flippantly replied "Write an abstraction layer so you don't care!". At this point another colleague who had been listening gave me one of those looks and said, "What?, write an abstraction layer on top of an abstraction layer, are you nuts!". At this point the conversation degenerated...

IoC containers are one of the latest “cool” new things in software development, and we all know how much we developers like “cool” new things and how hard we will work to find creative ways to implement them. This is emphasised by the fact that the question being asked was, which IoC framework should I use?, rather than what are the high level requirements? We also know, from experience that “cool” new things tend to have volatile APIs and capabilities for a while before they settle. During this period of volatility we also need to consider support, will the IoC container continue evolve and be supported?

Where should we use IoC containers?

We should use them where they will provide real benefit. Could everything in an application be accessed through an IoC container, probably..., should it, absolutely not, this smells of needless complexity. Try to take an incremental, test driven approach to development. Focus on creating maintainable solutions, whilst avoiding needless complexity. During initial increments the "new" operator may work just fine, as you progress it will become clear which classes have a lot of dependents and are subject to change, at this point you may abstract and refactor using Factory Pattern, and from the IoC. The point is, apply IoC when it is required, rather than wherever possible.

Which IoC container should I use?

I’m sticking to my guns on this one, the client shouldn’t care. By employing the Dependency Inversion Principle  (DIP), it is easy to remove any client dependencies.

Software consultant Robert C. Martin stated the DIP this way:

High level modules should not depend upon low level modules. Both should depend upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions.

Most software systems these days are organised into layers, the diagram below shows a naive implementation of a layered system and the its dependencies.

image

The problem with this approach is the dependency chain, changes to downstream components will affect their dependents. A solution to this is to invert the dependencies.

image

A more complete description can be found here The Dependency Inversion Principle

Now if we apply this principal to our IoC example:

image

The thing to remember here is that the diagram is showing how the dependencies should flow and does not necessarily imply an implementation. For example, the abstraction between the client and the service layer could be implemented as a simple static utility class, or utilise the Factory pattern, etc. The point is, there is no dependency on the IoC container.

Free Productivity Tools for Visual Studio

Got to see this in action at PDC and it looked pretty cool, it's also at my favourite price, i.e. free!!

http://blogs.msdn.com/charlie/archive/2008/10/29/coderush-xpress-for-c.aspx

Delegates Gotcha
Hit a small gotcha today whilst using delegates. Take a look at the following (contrived) example...
   1: public delegate object Getter();
   2:  
   3: public interface ITest
   4: {
   5:     Getter Getter
   6:     {
   7:         get;
   8:     }
   9: }
  10:  
  11: public class Test : ITest
  12: {
  13:     private object GetValue()
  14:     {
  15:         //    implementation....
  16:     }
  17:  
  18:     #region ITest Members
  19:  
  20:     public Getter Getter
  21:     {
  22:         get { return GetValue;  }
  23:     }
  24:  
  25:     #endregion
  26: }

 

If you examine the code you will spot the implementation of ITest.Getter returns a delegate pointing to the GetValue method. The code doesn't appear to be very complicated, surely not much is happening here? Well, not much, but enough to severally hit performance in my case. The thing is, this line of code results in the compiler creating and returning a delegate each and every time this property is accessed. This would be obvious if the compiler forced you to write "new Getter(GetValue)", however, since .NET 2.0 it doesn't. The simple fix is to cache the delegate as shown below...

   1: public delegate object Getter();
   2:  
   3: public interface ITest
   4: {
   5:     Getter Getter
   6:     {
   7:         get;
   8:     }
   9: }
  10:  
  11: public class Test : ITest
  12: {
  13:     private Getter getter;
  14:  
  15:     public Test()
  16:     {
  17:         getter = GetValue;
  18:     }
  19:  
  20:     private object GetValue()
  21:     {
  22:         //    implementation....
  23:     }
  24:  
  25:     #region ITest Members
  26:  
  27:     public Getter Getter
  28:     {
  29:         get { return getter;  }
  30:     }
  31:  
  32:     #endregion
  33: }

This fix reducing the time taken for an operation to run from 15 seconds down to 2 in something I was working on!!

Insert Code Snippet Plug-In for Live Writer

Unfortunately there are a few "Insert Code" plug-ins available live writer, some better than others (I was previously using the not so good one :( ). To save others the hassle of trying lots of different ones here is my recommendation http://gallery.live.com/liveItemDetail.aspx?li=d4409446-af7f-42ec-aa20-78aa5bac4748&bt=9&pl=8 It provides syntax highlighting, line numbering and best of all allows the code to be placed in a scrollable container which prevents the text from going out of view.