Phillip Trelford's Array

POKE 36879,255

C# 5 CallerMemberName from Silverlight & WPF 4.0

C# 5 allows you to obtain the method or property of the caller to a method using the CallerMemberName attribute under System.Runtime.CompilerServices in .Net 4.5:

using System.ComponentModel;
using System.Runtime.CompilerServices;

public class ObservableObject : INotifyPropertyChanged 
{
  protected void NotifyPropertyChanged([CallerMemberName] string name = null)
  {
    var e = PropertyChanged;
    if (e != null) e(this, new PropertyChangedEventArgs(name));
  }

  public event PropertyChangedEventHandler PropertyChanged;
}

This is particularly useful in XAML applications using WPF, Silverlight or WinRT that signal changes to properties via the INotifyPropertyChanged interface. With the new feature you don’t need to explicitly specify a literal string or lambda expression when notifying that a property has changed from it’s setter:

public class ViewModel : ObservableObject
{
  private object _value;

  public object Value
  {
    get { return _value; }
    set
    {
      _value = value;
      this.NotifyPropertyChanged();
    }
  }
}

Silverlight and earlier versions of the .Net Framework behind WPF do not have the CallerMemberName attribute. The good news is that you simply need to define it in yourself and assuming you’re using the C# 5 compiler then it just works:

namespace System.Runtime.CompilerServices
{
  /// <summary>
  /// Allows you to obtain the method or property name of the caller.
  /// </summary>
  [AttributeUsageAttribute(AttributeTargets.Parameter, Inherited = false)]
  public sealed class CallerMemberNameAttribute : Attribute { }
}

Silverlight 5 Native Modal Windows

Multiple Window support is new in Silverlight 5:

You can display multiple Window instances in trusted, out-of-browser applications. This enables you to create non-modal dialog boxes, tear-off windows, and user-adjustable layouts that can span multiple monitors.

Silverlight provides support for modal dialog boxes that work in-browser and out-of-browser against the main window, like the ChildWindow control. However Silverlight’s built-in support for native Modal Windows is limited to the MessageBox class

MessageBox

Silverlight’s MessageBox.Show static method can open a modal dialog box, which is good for error messages, but it looks a bit basic and you can’t modify it’s style:

MessageBox.Show

ShowDialog

WPF provides a Window.ShowDialog method:

ShowDialog shows the window, disables all other windows in the application, and returns only when the window is closed.

This mechanism allows you to provide your own styling on the window.

Using an extension method, Silverlight’s Window class can be extended with a ShowDialog method too. This can be implemented very concisely in F#:

type System.Windows.Window with
   member window.ShowDialog() = 
      async {
          // Show the window
          window.Show()
          // Disable all other windows
          allWindows() |> Seq.filter ((<>) window) |> Seq.iter disableWindow
          // Await window closing
          do! window.Closing |> Async.AwaitEvent |> Async.Ignore
          // Enable all other windows
          allWindows() |> Seq.filter ((<>) window) |> Seq.iter enableWindow
      } |> Async.StartImmediate

Win32 provides an EnableWindow function that we can P/Invoke:

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnableWindow(IntPtr hWnd, bool bEnable);

The EnableWindow function takes a handle to a Window. The code to find a window’s handle is available in the article Silverlight 5 Native Windows P/Invoke that I wrote earlier in the month. The article also demonstrates how a window can be removed from the taskbar which you may want to do for a dialog window.

ShowModal

The ShowDialog method disables all other windows while the Window is shown. Let’s look at a ShowModal extension method in C# that only disable’s the owner window:

public static class ModalWindowExtension
{
    public static void ShowModal(this Window modalWindow, Window ownerWindow)
    {
        ModalWindow.Show(modalWindow, ownerWindow);
    }
}

An internal class instance is required so that we can hook and unhook the Closing event:

internal class ModalWindow
{
    Action _close = () => { };

    internal static void Show(Window modalWindow, Window ownerWindow)
    {
        var instance = new ModalWindow();
        instance.Invoke(modalWindow, ownerWindow);
    }

    internal void Invoke(Window modalWindow, Window ownerWindow)
    {
        modalWindow.Closing += WindowClosing;

        var ownerHwnd = Win32.FindHwnd(ownerWindow);
        bool isOwnerEnabled = Win32.IsWindowEnabled(ownerHwnd);
        Win32.EnableWindow(ownerHwnd, false);

        _close = () =>
        {
            modalWindow.Closing -= WindowClosing;
            Win32.EnableWindow(ownerHwnd, isOwnerEnabled);
            _close = () => { };
        };

        modalWindow.Show();
    }

    private void WindowClosing(object sender, ClosingEventArgs e)
    {
        _close();
    }
}

The C# implementation has to deal with some extra accidental complexity as C# events are not first class, beside that the implementations are quite similar.

Summary

Adding native modal window support for Silverlight 5 out-of-browser applications is pretty easy using the WIn32 EnableWindow and an extension method.

A single line stack trace

This week I was assigned a bug with a single line stack trace:

Telerik.Windows.Controls.RadDocking.<>c__DisplayClass1b'::'<DropWindow>b__19
 

The exception type was of type NullReferenceException. The issue could be reproduced by repeatedly docking and undocking a window in the application for about 30 seconds. The result was an unhandled exception that took down the application.

The single line indicated that the exception originated somewhere in Telerik’s RadControls for Silverlight, probably a compiler generated class for a closure.

Ildasm

Ildasm is a tool that lets you look at the .Net IL code generated by the compiler. Looking at the Telerik Docking dll with Ildasm, the generated class and method can be seen:.

IL DASM - Telerik.Windows.Controls.RadDocking.c_DisplayClass1b

DropWindow_b_19

.method public hidebysig instance void 'b__19'() cil managed
{
 // Code size 18 (0x12)
 .maxstack 8
 IL_0000: ldarg.0
 IL_0001: ldfld class Telerik.Windows.Controls.RadPane 
  Telerik.Windows.Controls.RadDocking/'<>c__DisplayClass1b'::activePane
 IL_0006: callvirt instance class Telerik.Windows.Controls.RadPaneGroup 
  Telerik.Windows.Controls.RadPane::get_PaneGroup()
 IL_000b: callvirt instance bool [System.Windows]
  System.Windows.Controls.Control::Focus()
 IL_0010: pop
 IL_0011: ret
} // end of method '<>c__DisplayClass1b'::'b__19'

The IL code shows a PanegGroup property being accessed followed by a call to a Focus method. The c__Displayclass class name indicates a closure.

Source Code

Telerik’s source code contains a RadDocking class with a DockWindow method that contains a closure that calls SetFocus on PaneGroup. Bingo!

Dispatcher.BeginInvoke(() => activePane.PaneGroups.SetFocus());

Workaround

The workaround is a common one in C#, add a null check against the property (PaneGroups) before calling the method (SetFocus).

What can we learn?

This fatal exception was found in a third party framework, thankfully during development. Lets examine how this happened and what can be done

Null checks

Tony Hoare, inventor of QuickSort, speaking at a conference in 2009:

I call it my billion-dollar mistake.

The billon-dollar mistake is the invention of the null reference in 1965.

C# references are null by default, and nullability is implicit.

Are null references really a bad thing? – Top Answer on Stack Overflow:

The problem is that because in theory any object can be a null and toss an exception when you attempt to use it, your object-oriented code is basically a collection of unexploded bombs.

How could this be done differently?

In F# references are not nullable by default, and nullability is explicit via the Option type, i.e. this issue could be removed by design.

Mutation

The PaneGroup property is most likely initialized with a valid reference before the call to BeginInvoke. The BeginInvoke method adds the Action to a queue and call it some time in the future.

C# objects are mutable by default.

This means that the state of the PaneGroup property may be mutated (set to null) before the closure is called.

F# objects are immutable by default, i.e. this issue could be removed by design.

BeginInvoke

It looks like SetFocus is being called asynchronously as UI Duct Type to workaround another issue where focus can not be set until the control is initialized:

It’s a standing joke on my current Silverlight project that when something isn’t working, just try Dispatcher.BeginInvoke.

This issue would require a framework fix where you could specify the control that receives focus by default.

Asynchronous calls

As the call to the closure was asynchronous it would be added to a queue, and later processed. The act of adding the closure to the queue removes it’s calling context which makes debugging hard.

Conclusions

Just this single line stack trace demonstrates a cacophony of language and framework design issues. Nullability by default in C# makes code look like a collection of unexploded bombs. Add asynchronous calls to the mix and you have even more chances of triggering one of those bombs. Worse working around the framework often forces you to make asynchronous calls to workaround other issues. Finally when a bomb does go off you are left with very little information to diagnose it.

Is OOP really a good paradigm for modern asynchronous UI programming?