Monday, 27 April 2015

Decorate it

This blog post shows how to decorate controls of an existing WPF/Xaml UI with limited code changes. To achieve this WPF concepts like Adorners, Dependency Properties and ControlTemplates come into play.

Recently I worked on an application which was overloaded with input fields. To make it even worse user input (mostly into a TextBox) triggered internal calculations and the update of multiple dependent fields. To bring changed values to the users attention we decided to highlight the changed values by decorating controls (TextBox elements) whenever the displayed value is changed. The picture below shows a simplified version of the user interface. Input of the TextBox Distance Top updates the values Distance Ax, Distance Ay and Distance Az.



In short the following steps are necessary:

  1. Create an Attached Property to let controls register for/enable the highlight feature
  2. Create a ControlTemplate which is attached to existing controls
  3. Upon registration of an Attached Property register for TextChanged events
  4. Create an Adorner Class which holds the defined ControlTemplate as its only child
  5. Add an instance of Adorner to the TextBox's AdornerLayer.

Create Attached Property

The Attached Property mechanism is a mean to create Dependency Properties and reuse these properties from other elements. Layout constraints are a good example for these kind of properties (e.g. DockPanel.Dock="Top"...).

We need an Attached Property to let a TextBox declare that value changes should be highlighted.

//The property to enable highlight feature for a specific user control public static readonly DependencyProperty HighlightProperty = DependencyProperty.RegisterAttached("Highlight", typeof (Boolean), typeof (UIElement), new FrameworkPropertyMetadata(false, HighlightPropertySetCallback));
public static void SetHighlight(UIElement element, Boolean value) { element.SetValue(HighlightProperty, value); } public static Boolean GetHighlight(UIElement element) { return (Boolean)element.GetValue(HighlightProperty); }

Create a visual indicator using ControlTemplates

The appearance of our value changed notification is defined by a ControlTemplate. The template defines a white flash and positions it within a blue colored ellipse shape. It should look something like this .
<ControlTemplate x:Key="HighlightTemplate">
<DockPanel Name="in">            
<Grid DockPanel.Dock="Right" Width="16" Height="16" VerticalAlignment="Center" Margin="3 4 0 0">
<Ellipse Width="16" Height="16"> <Ellipse.Fill>
</Ellipse>
<SolidColorBrush  x:Name="brush" Color="SteelBlue"></SolidColorBrush></Ellipse.Fill>
<Polyline.Fill>
<Polyline  VerticalAlignment="Top" HorizontalAlignment="Center" StrokeThickness="0"  Margin="0 2 0 0" Points="3,0,6,0,5,5,8,5,3,14,4,8,1.5,8,3,0">
<SolidColorBrush  x:Name="arrowBrush" Color="White"></SolidColorBrush>
<controltemplate>
</Polyline.Fill>
</Polyline>
</Grid>
</DockPanel>

Register on value changes

In the first snippet we registered a callback method upon setting the attached property. What the callback method does is to register for TextChanged events of the given TextBox.
private static void HighlightPropertySetCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
     //get target textbox
     TextBox textBox = dependencyObject as TextBox;
     if (textBox == null) 
     {        
         return;
     }
     //Register on text changed
     textBox.TextChanged += OnTextBoxChanged;
}
Upon text changed we will add an Adorner to our TextBox's Adornerlayer. But first, we need to create an Adorner which holds the ControlTemplate presented above.

Create an Adorner to display the ControlTemplate

The following snippet shows the implementation of the Adorner used to decorate the TextBox with the shown ControlTemplate.
public class PresentationAdorner : Adorner
{
    private Control child;

    public Control Child
    {
        get { return child; }

        set
        {
            if (child != null)
            {
                RemoveVisualChild(child);
            }
            child = value;
            if (child != null)
            {
                AddVisualChild(child);
            }
        }
    }
    
    public PresentationAdorner([NotNull] UIElement adornedElement) : base(adornedElement) { }

    protected override int VisualChildrenCount
    {
       get { return 1; }
    }

    protected override Visual GetVisualChild(int index)
    {
       if (index != 0) throw new ArgumentOutOfRangeException();
       return child;
    }

    protected override Size MeasureOverride(Size constraint)
    {
       child.Measure(constraint);
       return child.DesiredSize;
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        child.Arrange(new Rect(new Point(0, 0), finalSize));
        return new Size(child.ActualWidth, child.ActualHeight);
    }
}
The implementation needs to be derived from Adorner. Typically Adorner implementation override the OnRender method and directly draw on the passed DrawingContext. In our case the appearance of the Adorner is defined by the ControlTemplate shown above. The template is set as the Adorners only visual child. Reseting the adorners Child property will remove any previously added visual child. Methods MeasureOverride and ArrangeOverride derive Size an Position of the Adorner from its Child Property.

Add Adorner to AdornerLayer on TextChanged

private static void OnTextBoxChanged(object sender, TextChangedEventArgs args)
{
    var textbox = sender as TextBox;
    if (textbox == null)
    {
        return;
    }

    //Get the adorner layer. Be sure your Application has one.
    AdornerLayer layer = AdornerLayer.GetAdornerLayer(textbox);
    if (layer == null)
    {
        return;
    }

    //Get the control template from resources.
    var controlTemplate = Application.Current.Resources["HighlightTemplate"] as ControlTemplate;
    if (controlTemplate == null)
    {
        return;
    }

    //Get allready existing adorner from adorner layer
    var adorners = layer.GetAdorners(textbox);
    if (adorners != null)
    {
        var presentationAdorner = adorners.OfType().First();
        if (presentationAdorner != null)
        {
            presentationAdorner.Child = new Control { Template = controlTemplate, Focusable = false, };
        }
    }
    else
    {
        // Or create a new adorner and add it to the layer
        var adorner = new PresentationAdorner(textbox);
        adorner.Child = new Control { Template = controlTemplate, Focusable = false, };
        layer.Add(adorner);
    }
}

Code above is executed whenever the text of a registered TextBox changes. If the AdornerLayer contains no Adorner of type PresentationAdorner a new instance is created and the Adorner's Child property is set to a Control holding the ControlTemplated shown above.

Be sure that your application provides an AdornerLayer by using an AdornerDecorator element within the applications ui element hierarchy. The AdornerLayer provides the static method GetAdorners to retrieve all Adorners for a specific ui element.

The screenshot above shows our example application after the value in Distance Top changed. For the sake of brevity the implementation shown in this blog post is rather simple and has many limitations (Decorations are not removed once a value change occured, decorations also appear on the control the user entered a value, the ControlTemplate for decorations is hardcoded and cannot changed, ... and many more).

However, for a start I hope this blog helps if you need to add decorations to controls.

Saturday, 21 March 2015

Debugging a Visual Studio Addin

Some time ago (1-2 years) I extended Microsoft Visual Studio 2010 for some custom functionality. I chose to create an Add-In which hooks a command into the solution explorer's context menu, execute some command action and provide user feedback via the output view and error list view.

Recently, I had to update this behaviour, which was quickly done. However, the thing that took me the longest was to find out again how to debug the Add-In from Visual Studio 2010. So primarily for myself :) I want to document the required steps in the following.

How to debug Visual Studio Add-In 

  1. Open your Add-In solution in Visual Studio 2010 
  2. Right mouse click the Add-In project file (.prj) and mark it as "startup project"
  3. Open project properties for your Add-In project. On tab Debug in section Start external program select the devenv.exe from your Visual Studio install
    Visual Studio 2010 project properties
  4. In section command line arguments use /resetaddin yourAddin.addin to force complete (re)initialisation of your Add-In 
  5. Copy your Add-In file (.AddIn) to Visual Studio 10's Add-In folder (i.e.  c:\users\<localuser>\Documents\Visual Studio 10\adddins)
  6. In the copied addin file use the <Assembly> tag to point to the Debug directory of your Add-In project.
  7. Run debug command for your Add-In project from Visual Studio 2010

Links


Tuesday, 7 October 2014

Lambdas killed progam code understandability

A short note on how the usage of advanced language features like lambda expressions might destroy a development teams ability to fully understand a codebase.



Currently I code in C# and I love lambdas. So do many of my team members. The project I am partly involved in started out as a C# 3.0 project and over the years evolved to using version 4.5. Although available right from the beginning it took some time until the usage of lambda expressions within our project picked up and by now I would say  2 third of us use lambda expression. However, the other third still opposes the use of lambda expressions. Those team members mostly argue that they wanted to stick to what they are used to and find lambdas less readable. Actually, these statements should have already sounded the alarm. What happened then was that over the last couple of month we saw a number of issues and bugs pop up which were rooted in the misinterpretation of code. When we analyzed these issues we learned that people who did not use lambda expressions themselves could not understand what the code does and therefore misused code or created code duplicates. Some developers even stated that they somehow blind out lambda expressions!

I found this quite worrying. Starting off with a code-base all team members had a shared understanding of, we came to the point where a significant number of developers could not fully understand our own codebase.

We write coding guidelines which define the number of characters a source code line should not exceed or how if statements are formatted to improve the readability of code. But we completely miss out on defining which language features should be used or better not be used to assure understandability of program sources.

Heavily nested procedural control flow structures are what we programmers who grew up with C++, Java and C# understand. By now however, all of those programming languages saw the introduction of some kind of syntax to define anonymous functions (lambdas in Java 8C# and C++11). I don't know what the solution to this should be, it will depend on many things like the education of developers, codebase, available tool support, the team approach to change or willingness to learn. But whatever the answer to use or not use advanced/new language features is, I am sure a conscious decision and discussion on the problems that might arise helps to preserve understandability of program code.