Thursday, 23 July 2009

Documenting Attached Properties with Sandcastle

I’ve been using Sandcastle and Sandcastle Help File Builder (SHFB) recently to produce some SDK documentation and noticed that topics were automatically created for attached properties like the one shown here. But how do you actually populate these topics and how do you link back to them? Well let’s work through a simple example.

/// <summary>
/// Identifies the MyAttached attached property.
/// </summary>
public static readonly DependencyProperty MyAttachedProperty = 
  DependencyProperty.RegisterAttached("MyAttached", typeof(string), typeof(MyClass));

public static string GetMyAttached(DependencyObject element)
{
  // Argument validation omitted.
  return (string)element.GetValue(MyAttachedProperty);
}

public static void SetMyAttached(DependencyObject element, string value)
{
  // Argument validation omitted.
  element.SetValue(MyAttachedProperty, value);
}

With attached properties there’s no physical property in the code for you to document. The only members that can be documented with the code are the dependency property field and the get/set helper methods. So how do you add documentation to the attached property topic? Well you can manually create an additional XML comment file for the assembly containing the attached property and add the following content:

<?xml version="1.0"?>
<doc>
  <assembly>
    <name>MyTest</name>
  </assembly>
  <members>
    <member name="P:MyTest.MyClass.MyAttached">
      <summary>Summary for MyAttached attached property.</summary>
    </member>
  </members>
</doc>

Add the XML comment file to the Documentation Sources of your SHFB project and the summary comments will appear in the attached property topic when the project is rebuilt. But what about linking back to the attached property topic from the dependency property field’s summary comment? Unfortunately the C# compiler will warn about both of the following:

/// <summary>
/// Identifies the <see cref="MyAttached" /> attached property.
/// </summary>

/// <summary>
/// Identifies the <see cref="MyTest.MyClass.MyAttached" /> attached property.
/// </summary>

In both cases the compiler warns that it cannot find a member matching the member specified in the see tag. This shouldn’t be that surprising because we already know there’s no physical property in the code. Sandcastle will therefore be unable to provide a link and the resulting text will appear as bold.  Fortunately there is a way to provide a valid member reference for the attached property, in fact we’ve already done so in the separate XML comment file.

/// <summary>
/// Identifies the <see cref="P:MyTest.MyClass.MyAttached" /> attached property.
/// </summary>

Now the C# compiler is happy and Sandcastle can generate a link back to the attached property topic.

Tuesday, 14 July 2009

The Dispose Pattern in C++/CLI

In my last post I talked about implementing events in C++/CLI. I also briefly mentioned that the C++/CLI team went to great lengths to correctly implement the dispose pattern as described in the Framework Design Guidelines, using the familiar C++ destructor syntax. This syntax is well documented so I won’t bother to go into detail about it, instead I’m going to focus on a quirk you’ll see when deriving from a class with a destructor. Here’s what you’ll see in a derived C# class when overriding the Dispose method.

protected override void Dispose(bool __p1)
{
  // Dispose implementation omitted.
  base.Dispose(__p1);
}

Clearly someone thought a single underscore wasn’t enough J. Somewhat surprisingly, there are no warnings generated for the __p1 parameter when code analysis is enabled, although I guess it explains how the parameter name slipped through in the first place. It could be that the code analysis tool knows the dispose pattern is being generated by the compiler and so ignores it completely, but I’m only speculating.

So will they fix it in a future release? I think it’s unlikely. Why? Changing the parameter name would result in a breaking change when class libraries are recompiled with the new compiler. So is it likely users of languages with support for named parameters are referring to the __p1 parameter by name? Probably not but Microsoft’s track record on breaking changes is to avoid them unless they’re required to fix a security vulnerability, so I think this will remain as a quirk of C++/CLI.

Friday, 10 July 2009

Implementing Events with C++/CLI

I’ve been doing a fair amount of work in C++ recently, using C++/CLI for interop between managed and unmanaged code. I found a minor problem when implementing events in a class library that I thought I’d share. As with C# you have a couple of options for events: use the data member syntax or define individual event accessor methods. Just like C# the former approach is nice and simple whereas the latter approach provides more flexibility. Unfortunately it’s the former approach that has the problem. Consider the following example:

public ref class MyClass
{
public:
  event System::EventHandler<MyEventArgs ^> ^MyEvent;
 
  // Remainder of MyClass omitted.
};

With this syntax the compiler will automatically produce the add, remove and raise event accessor methods. The latter is protected so that derived classes can also raise the event, and this is where the problem occurs. There’s already a well defined pattern that class library authors should implement to allow derived classes to raise events defined in a base class. Unfortunately the data member event syntax in C++/CLI doesn’t follow this pattern. The following C# snippets show the recommended pattern and the equivalent of what the C++/CLI compiler produces:

// Recommended method for raising MyEvent.
protected virtual void OnMyEvent(MyEventArgs e)
{
  // Raise event.
}

// Method for raising MyEvent produced by C++/CLI compiler.
protected void raise_MyEvent(object sender, MyEventArgs e)
{
  // Raise event.
}

The C++/CLI compiler produces a method that, in addition to having an ugly name, only allows derived classes to raise the event. Derived classes cannot handle the event without attaching their own event handler . When you consider the lengths the C++/CLI team went to implement the dispose pattern as described in the Framework Design Guidelines, it’s surprising they didn’t provide the same support for events. Fortunately, although somewhat tediously if you have a large number of events, you can overcome this limitation by defining the individual event accessor methods as well as the correct virtual method for derived classes. You’ll also need to provide the backing field for the event.

public ref class MyClass
{
public:
  event System::EventHandler<MyEventArgs ^> ^MyEvent
  {
  public:
    void add(System::EventHandler<MyEventArgs ^> ^value);
    void remove(System::EventHandler<MyEventArgs ^> ^value);

  private:
    void raise(System::Object ^sender, MyEventArgs ^e);
  }
 
protected:
  virtual void OnMyEvent(MyEventArgs ^e);

private:
  System::EventHandler<MyEventArgs ^> ^m_myEvent;

  // Remainder of MyClass omitted.
};

It’s a shame you have to jump through these hoops to implement a pattern that has existed since the first version of the .NET Framework. I also mentioned the lengths the C++/CLI team went to implement the dispose pattern earlier. Unfortunately this too has a problem, albeit a minor one, that I’ll talk about in the next post.

Thursday, 19 February 2009

Restricting the Contents of Container Controls

It’s quite common for container controls to place a restriction on the type of child controls they contain. For example, the TabControl class will only accept instances of the TabPage class as children. These controls will typically expose a type-safe collection to prevent users from adding the wrong type of child control. This is not a complete solution however, because it’s also possible to add child controls using the Controls property. In fact, this is exactly how the designer-generated initialisation code adds child controls. To prevent any bypassing of the child control restrictions you should override the CreateControlsInstance method and return a more specialised control collection that provides the correct behaviour for adding and removing child controls. Consider the following example, where the CustomPanel control is prohibited from having another CustomPanel control as a child control.

public class CustomPanel : Panel
{
  protected override Control.ControlCollection CreateControlsInstance()
  {
    return new CustomPanelControlCollection(this);
  }

  private class CustomPanelControlCollection : Control.ControlCollection
  {
    public CustomPanelControlCollection(CustomPanel owner)
      : base(owner)
    {
    }

    public override void Add(Control value)
    {
      if (value is CustomPanel)
      {
        throw new ArgumentException(
          "Cannot add a CustomPanel control to another CustomPanel control.", 
          "control");
      }
      base.Add(value);
    }

    public override void Remove(Control value)
    {
      base.Remove(value);
      if (value is CustomPanel)
      {
        // Additional remove code omitted.
      }
    }
  }

  // Remainder of CustomPanel omitted.
}

I’ve overridden the Remove method for completeness, but it can be omitted if there’s no need to perform any additional work when removing child controls from the collection. What about the other methods that can be used for adding and removing child controls? Well the AddRange method and the implementation of the IList.Add method call the virtual Add method. It’s not possible to add child controls at any position other than the end of the collection, so the implementation of the IList.Insert method and the setter for the IList.Item property both throw NotSupportedException. The Clear, RemoveAt, RemoveByKey methods and the implementation of the IList.Remove method all call the virtual Remove method.

This means we only need to override the Add and Remove methods as shown above, but it also highlights a weakness with the design of the Control.ControlCollection class. When you have multiple virtual methods calling other virtual methods it can be difficult for inheritors to know which methods they should override. You’ll probably learn by unit testing the cases mentioned above or simply by using a tool such as Reflector, but in both cases what you’re learning about is the implementation details of the Control.ControlCollection class. It’s unfortunate when classes leak implementation details like this because it always leaves you with a problem. You can take the approach demonstrated above and hope that the Windows Forms team doesn’t change the implementation in a way that breaks your collection. Alternatively you can override and seal the other virtual methods and re-implement any relevant explicitly implemented interface members to produce the desired call chain. Unfortunately preserving the contract of the overridden methods can be more difficult than it first seems, especially if the base class implementations have access to members that are not accessible from derived classes. I think the former approach is the lesser of two evils based on the trend for minimising breaking changes in the .NET Framework, but YMMV.

Wednesday, 18 February 2009

Declaring Default Values for Control Properties

Default values for properties must be documented to make users aware of a control’s default state. This information is also useful for visual designers and code generators. A visual designer can use the default value to perform a “reset” in the property grid, and a code generator can use the default value to determine whether or not it should persist the property in designer-generated initialisation code.

Consider the following example, where the CustomListView control exposes a hover delay for generating a hover event during a drag-and-drop operation.

public class CustomListView : ListView
{
  private int m_dragHoverTime = 400;

  public int DragHoverTime
  {
    get { return m_dragHoverTime; }
    set { m_dragHoverTime = value; }
  }

  // Remainder of CustomListView omitted.
}

The default value of 400 milliseconds can be documented but a visual designer will not be aware of this value. This results in the property being displayed in bold in the Visual Studio property grid, which indicates a non-default value. The value is also persisted in the designer-generated initialisation code. Use the DefaultValueAttribute class to advertise the default value of a property to visual designers and code generators.

public class CustomListView : ListView
{
  private const int DefaultDragHoverTime = 400;
  private int m_dragHoverTime = DefaultDragHoverTime;

  [DefaultValue(DefaultDragHoverTime)]
  public int DragHoverTime
  {
    get { return m_dragHoverTime; }
    set { m_dragHoverTime = value; }
  }

  // Remainder of CustomListView omitted.
}

With this approach the control’s hover delay time is only persisted in designer-generated initialisation code if it is different from the default value. Similarly, a visual designer will display the value correctly in the property grid and will also be able to perform a reset back to the default value. It’s worth noting that there’s a system-defined hover delay value returned by the SystemInformation.MouseHoverTime property. This seems like a better candidate for a default value than the previous 400 millisecond value. Unfortunately, it’s not possible to use this value with the DefaultValueAttribute class but there is another option – the ShouldSerialize and Reset methods pattern.

public class CustomListView : ListView
{
  private int m_dragHoverTime = SystemInformation.MouseHoverTime;

  public int DragHoverTime
  {
    get { return m_dragHoverTime; }
    set { m_dragHoverTime = value; }
  }

  private bool ShouldSerializeDragHoverTime()
  {
    return DragHoverTime != SystemInformation.MouseHoverTime;
  }

  private void ResetDragHoverTime()
  {
    DragHoverTime = SystemInformation.MouseHoverTime;
  }

  // Remainder of CustomListView omitted.
}

This still isn’t ideal because the value returned by SystemInformation.MouseHoverTime reflects a system-wide parameter that can vary across machines. This could result in unpredictable behaviour when using visual designers in a team environment. For example, resetting to the default value on one developer’s machine could result in another developer seeing a non-default value on their machine. Even so, it seems wrong not to provide developers with the facility to use the system-defined value. At this point you might be asking “Why not always used the system-defined value?” That’s definitely a sensible strategy, in which case you don’t even need to expose the DragHoverTime property. But we haven’t come this far just to ditch the property J. The actual scenario where I’ve used something similar to this example before involved using the system-defined value in all but one place. The exception was where usability feedback demonstrated that the system-defined value wasn’t long enough for the desired user interaction. The solution was to provide a UseSystemMouseHoverTime property to indicate whether or not the control should use the system-defined value or its own value, which means we can go back to the DefaultValueAttribute class after all J.

public class CustomListView : ListView
{
  private const int DefaultDragHoverTime = 400;
  private int m_dragHoverTime = DefaultDragHoverTime;
  private bool m_useSystemMouseHoverTime = true;

  [DefaultValue(DefaultDragHoverTime)]
  public int DragHoverTime
  {
    get { return m_dragHoverTime; }
    set { m_dragHoverTime = value; }
  }

  [DefaultValue(true)]
  public bool UseSystemMouseHoverTime
  {
    get { return m_useSystemMouseHoverTime; }
    set { m_useSystemMouseHoverTime = value; }
  }

  // Remainder of CustomListView omitted.
}

Obviously that’s a very specific scenario, but the key thing to remember is that you should make sure your controls have sensible defaults and that those defaults are properly reflected in a designer.

Friday, 13 February 2009

Hiding Base Class Members in Controls

Even when you pick your base class wisely, it’s entirely possible for the base class to contain properties and/or events that are not meaningful for your custom control. Having these members available at design-time via a visual designer’s property grid or a code editor’s IntelliSense makes it harder for API users to spot the genuinely useful members. Consider the CustomPanel control below, where the size and enabled state are determined by the control’s parent. There’s no point advertising the AutoSize and Enabled properties for this control, so we should hide them.

public class CustomPanel : Panel
{
  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  [EditorBrowsable(EditorBrowsableState.Never)]
  public override bool AutoSize
  {
    get { return base.AutoSize; }
    set { base.AutoSize = value; }
  }

  [Browsable(false)]
  [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
  [EditorBrowsable(EditorBrowsableState.Never)]
  public new bool Enabled
  {
    get { return base.Enabled; }
    set { base.Enabled = value; }
  }

  // Remainder of CustomPanel omitted.
}

The following attributes have been used to hide the properties at design-time.

Defining the attributes on the AutoSize property is straightforward since it is virtual and can be overridden. The Enabled property is non-virtual so we cannot define the attributes on this property and must instead create another Enabled property to hide the inherited one. In both cases the original contract is preserved by calling through to the base class members.

When hiding members it is also important to consider any related members such as events. In the above example, we must consider the property changed events for AutoSize and Enabled properties, which will still be visible at design-time. The same techniques used for both properties are also applicable to their events as shown below.

public class CustomPanel : Panel
{
  [Browsable(false)]
  [EditorBrowsable(EditorBrowsableState.Never)]
  public new event EventHandler AutoSizeChanged
  {
    add { base.AutoSizeChanged += value; }
    remove { base.AutoSizeChanged -= value; }
  }

  [Browsable(false)]
  [EditorBrowsable(EditorBrowsableState.Never)]
  public new event EventHandler EnabledChanged
  {
    add { base.EnabledChanged += value; }
    remove { base.EnabledChanged -= value; }
  }

  // Remainder of CustomPanel omitted.
}

Windows Forms controls should follow the event pattern described in the Framework  Design Guidelines and raise their events from protected virtual methods. You should consider hiding these methods as well but in practice, hiding these members is unnecessary since it will still be useful for derived controls to interact with these events even when they’ve been hidden from the designer/code editor.

It is important to reiterate that the motivation for hiding base class members is to prevent meaningless members from appearing at design-time. It is not the intention to enforce runtime restrictions because we should always preserve the contract of the base class members. This is why neither property setter throws an exception.

Thursday, 12 February 2009

Implementing Observable Objects – Part VI

In Part V I mentioned that the ObservableItem class makes no checks to ensure any UI updates are made on the correct thread, which means it could potentially violate the threading model employed by both Windows Forms and WPF. Now if you spent much time working with WPF you’re probably aware that the data binding mechanism can actually cope with PropertyChanged events raised on different threads to the bound UI object. Windows Forms on the other hand will dutifully throw an InvalidOperationException in the same scenario if the CheckForIllegalCrossThreadCalls property is set to true. So if you only want to target WPF then you can get away with doing nothing, but I wouldn’t recommend this approach. Firstly, if you later discovered you needed to use the same data model with Windows Forms you might find it to be a non-trivial change, especially if other WPF dependencies have crept in. I know this appears to violate the YAGNI approach but we’re not really talking about adding unnecessary functionality, we’re trying not to unnecessarily prohibit reuse of the data model. Secondly, dealing with concurrency is hard enough without letting it ambush you J. I’m not saying you should never perform data model operations on a background thread, but you should always ensure that any resulting UI updates are marshalled to the correct thread. We can ensure we’re on the correct thread by making the following modifications to the ObservableItem class:

private readonly Thread m_synchronizationThread = Thread.CurrentThread;
private PropertyChangedEventHandler m_propertyChangedEventHandler;

public event PropertyChangedEventHandler PropertyChanged
{
  add
  {
    VerifySynchronizationThread();
    m_propertyChangedEventHandler += value;
  }
  remove
  {
    VerifySynchronizationThread();
    m_propertyChangedEventHandler -= value;
  }
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void SetPropertyInternal<T>(
  string propertyName, ref T field, T value, IEqualityComparer<T> comparer)
{
  if (VerifySetPropertyArguments)
  {
    VerifySetPropertyInternalArguments(propertyName, comparer);
  }
  VerifySynchronizationThread();
  if (!comparer.Equals(field, value))
  {
    T oldValue = field;
    field = value;
    try
    {
      OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }
    catch
    {
      field = oldValue;
      throw;
    }
  }
}

private void VerifySynchronizationThread()
{
  if (m_synchronizationThread != Thread.CurrentThread)
  {
    throw new InvalidOperationException(
      "The current object is being updated on a thread that is different from the " + 
      "thread it was created on.");
  }
}

Now whenever the SetPropertyInternal method is called or an event handler is registered or unregistered for the PropertyChanged event, the VerifySynchronizationThread method is called to ensure we’re on the correct thread. This protects us from unintentional UI updates on another thread, but what about when we need a data model object to perform a potentially long running operation on a background thread? Clearly we don’t want to be calling methods such as Control.Invoke or Dispatcher.Invoke from data model objects because that would tie us to either Windows Forms or WPF. This is where the SynchronizationContext class comes in, which allows us to Send (synchronous) or Post (asynchronous) updates to the UI correctly. Consider the following addition to the Person class:

public void LongRunningOperation()
{
  var currentContext = SynchronizationContext.Current;
  if (currentContext == null)
  {
    currentContext = new SynchronizationContext();
  }
  ThreadPool.QueueUserWorkItem(
    new WaitCallback(
      state1 =>
      {
        string processedFirstName = GetUpperLowerString(FirstName);
        string processedLastName = GetUpperLowerString(LastName);
        currentContext.Post(
          new SendOrPostCallback(
            state2 =>
            {
              FirstName = processedFirstName;
              LastName = processedLastName;
            }), 
          null);
      }));
}

private static string GetUpperLowerString(string value)
{
  var result = new StringBuilder(value.Length);
  for (int i = 0; i < value.Length; ++i)
  {
    string textElement = StringInfo.GetNextTextElement(value, i);
    result.Append((i % 2) == 0 ? 
      textElement.ToUpperInvariant() : 
      textElement.ToLowerInvariant());
  }
  return result.ToString();
}

Now I’ve cheated a little here since my “long running” operation does nothing more than alternate the case of characters in the FirstName and LastName properties J. We use the SynchronizationContext.Current property to return a SynchronizationContext object that will update the FirstName and LastName properties, and therefore any data bound view, on the correct thread. If the property returns null then we use a default SynchronizationContext. We do this because if the default SynchronizationContext doesn’t do the correct thing, which is likely, then the resulting InvalidOperationException will be more helpful than a NullReferenceException. I’ve added a button to both sample applications so that you can test this exciting functionality out J.

Now you might be wondering why we don’t store the current SynchronizationContext instead of the current thread. Unfortunately we’re unlikely to get the same instance back in a WPF application due to the way WPF sets the current SynchronizationContext and because none of the derived classes override the Equals method, reference equality is all we can use.

Well I think that’s enough on this topic, at least for a little while J. I promise the next post will be about something different.