Watermark TextBox in Windows Store apps

A common request for WSAs is to add a “watermark” to TextBox entries so users get a hint as to what is expected in the TextBox. You can see this in many Search Charm implementations as it allows a search hint to be provided via the SearchPane.PlaceHolderText property.  However, the built-in TextBox in XAML doesn’t have this feature (HTML does!).

There are a few custom controls out there which allow for this, however, I’m a big fan of behaviors over custom controls – so when I needed this, I created a custom behavior to apply to any existing XAML TextBox to provide a watermark:

The behavior sets the text to the watermark and then watches for focus changes to add/remove the text when there is no existing text entered.  It has two forms of activation – either you can add it to the normal Interaction.Behaviors collection:

<TextBox ...>
   <si:Interaction.Behaviors>
      <i:WatermarkTextBehavior WatermarkColor="Red" WatermarkText="Search Keyword..." />
   </si:Interaction.Behaviors>
</TextBox>

Here, the main advantage is you can set the watermark text color. The default is a gray color. Alternatively, you can use an attached property (Text) which will add a new behavior to the TextBox without needing the full syntax:

<TextBox ...
   i:WatermarkTextBehavior.Text="Search Keyword...">
</TextBox>

The code is part of the latest MVVMHelpers library and is checked in at: WatermarkTextBoxBehavior.cs.   The plan is to include it in the next Nuget drop, until then you can download the source and use it in your project directly if desired!

Enjoy!

Variable sized tiles in Windows Store Apps

One of the common requests I hear when training customers on Windows 8 is “How do I create variable sized tiles in a GridView?” The Windows Store app utilize this technique where different tiles have different sizes to promote content.

It turns out this is relatively easy in HTML – which is probably one of the reasons Microsoft chose to use that visual platform to build the app.  In XAML however, this is a bit more difficult.  There are many posts which detail using a VariableSizeWrapGrid with a GridView to achieve a similar effect – I like Mike Taulty’s blog on the approach.  And this does work as long as you don’t want to have different sized rows and columns, and you don’t have too many items.  The problem is that the VariableSizeWrapGrid doesn’t support virtualization or incremental loading – both key technologies if you have a lot of items.

An alternative approach to this is to do the layout yourself and use a Canvas as the panel – in this sense, you (the programmer) have to manage the layout and it’s not done automatically as rows and columns, but the upside is you have complete control over the layout and performance is greatly improved.

For a test, I chose to enumerate the available colors and then randomly create rows and columns – here’s a single run:

Notice that in this case the sample has two items side-by-side in the same column, and also has different sized columns and items that span rows – in fact, because I’m using a Canvas as my panel, I can use any sized element I choose – I’m not required to enforce columns and rows at all like I am with the grid-based panels.

The code is relatively straight-forward – I’m using MVVM so I put the Top/Width/Height into properties on the ColorViewModel:

public sealed class ColorViewModel : SimpleViewModel
{
    #region Data
    private int _heightPercent;
    private double _height, _width;
    private double _top, _left;
    #endregion

    /// <summary>
    /// Color for this item
    /// </summary>
    public string Color { get; set; }

    /// <summary>
    /// Index of the item (used for label)
    /// </summary>
    public int Index { get; set; }

    /// <summary>
    /// Row for the item (used for label)
    /// </summary>
    public int Row { get; set; }

    /// <summary>
    /// Column for the item (used for label)
    /// </summary>
    public int Col { get; set; }

    /// <summary>
    /// Left position relative to (0,0).
    /// </summary>
    public double Left
    {
        get { return _left; }
        set { SetPropertyValue(ref _left, value); }
    }

    /// <summary>
    /// Top position - changes when the Height of the GridView
    /// is altered (i.e. screen orientation)
    /// </summary>
    public double Top
    {
        get { return _top; }
        set { SetPropertyValue(ref _top, value); }
    }

    /// <summary>
    /// Width of this item
    /// </summary>
    public double Width
    {
        get { return _width; }
        set { SetPropertyValue(ref _width, value); }
    }

    /// <summary>
    /// Height to use for this item - calculated by the MainViewModel
    /// once it knows the actual height of the GridView using the Height %
    /// </summary>
    public double Height
    {
        get { return _height; }
        set { SetPropertyValue(ref _height, value); }
    }

    /// <summary>
    /// How much of the height to take up as a %
    /// </summary>
    public int HeightPercent
    {
        get { return _heightPercent; }
        set { SetPropertyValue(ref _heightPercent, value); }
    }

    /// <summary>
    /// This indicates if the cell is shared with another item in the
    /// same column/row (side-by-side)
    /// </summary>
    public bool IsSplitCell { get; set; }

    /// <summary>
    /// Returns a string that represents the current object.
    /// </summary>
    public override string ToString()
    {
        return string.Format("{0}: {1} ({2}x{3}) {4}% [{5},{6}]", Index, Color, Width, Height, HeightPercent, Col, Row);
    }
}

These properties are then calculated by the MainViewModel for each of the known colors – the position is randomly determined here just for example purposes, presumably in a real application (such as the Windows Store app) there would be an XML data file pulled from a server to display the data – but in any case there would be an known row/column and size for each element. Note there is a little code at the end of each loop iteration to ensure we always end the height of the column at 100%. The two important bits of code here are the ViewHeight property and the constructor which loads the items.

public sealed class MainViewModel : SimpleViewModel
{
    #region Data
    private readonly Random _rng = new Random();
    private double _viewHeight = Double.NaN, _viewWidth;
    private readonly List<ColorViewModel> _backingStore;
    #endregion

    /// <summary>
    /// This is set to the actual height of the panel 
    /// it then calculates the proper height and top of each item
    /// </summary>
    public double ViewHeight
    {
        get { return _viewHeight; }
        set
        {
            SetPropertyValue(ref _viewHeight, value);

            double top = 0;
            for (int index = 0; index < _backingStore.Count; index++)
            {
                var cvm = _backingStore[index];
                if (cvm.Row == 0)
                    top = 0;

                cvm.Height = _viewHeight*(cvm.HeightPercent/100.0)*.9;

                if (index > 0 && _backingStore[index - 1].IsSplitCell)
                {
                    cvm.Top = _backingStore[index - 1].Top;
                }
                else
                {
                    cvm.Top = top;
                    top += cvm.Height;
                }
            }
        }
    }

    /// <summary>
    /// The calculated width of the panel - this is required so we get scrollbars in the GridView.
    /// </summary>
    public double ViewWidth
    {
        get { return _viewWidth; }
        set { SetPropertyValue(ref _viewWidth, value); }
    }

    /// <summary>
    /// The list of colors
    /// </summary>
    public IList<ColorViewModel> Colors { get; private set; }

    /// <summary>
    /// Constructor
    /// </summary>
    public MainViewModel()
    {
        _backingStore = typeof(Colors).GetTypeInfo().DeclaredProperties
                                        .Select(p => new ColorViewModel { Color = p.Name })
                                        .ToList();

        int currentColumn = 0;
        double currentWidth = 0;

        // Calculate the position of each item. 
        for (int i = 0; i < _backingStore.Count; )
        {
            int columnWidth = _rng.Next(200, 500);
            int numberOfColors = _rng.Next(1, 7);
            int trackPct = 0;

            // Create a single column
            for (int c = 0; c < numberOfColors && trackPct < 95 && i < _backingStore.Count; i++, c++)
            {
                ColorViewModel cvm = _backingStore[i];
                cvm.Index = i + 1;
                cvm.Col = currentColumn;
                cvm.Row = c;
                cvm.Left = currentWidth;

                // Decide the height of this item.
                int maxH = Math.Min(100 - trackPct, 100/numberOfColors);
                int h = _rng.Next(15, maxH);

                // Allow it to share row with second item
                if (c > 0 && _backingStore[i-1].IsSplitCell)
                {
                    var previousCell = _backingStore[i - 1];
                    cvm.Left = previousCell.Left + previousCell.Width;
                    cvm.Width = previousCell.Width;
                    cvm.HeightPercent = previousCell.HeightPercent;
                    c--;
                }
                else
                {
                    trackPct += h;
                    cvm.HeightPercent = h;

                    if (c > 0 && numberOfColors > 2 && _rng.Next(4) == 1) // 1/4 chance
                    {
                        cvm.Width = (columnWidth / 2.0) - 5;
                        cvm.IsSplitCell = true;
                    }
                    else
                        cvm.Width = columnWidth;
                }
            }

            // Make sure we always end on 100%
            _backingStore[i - 1].HeightPercent += 100 - trackPct;
            _backingStore[i - 1].Width = columnWidth;
            _backingStore[i - 1].IsSplitCell = false;

            currentColumn++;
            currentWidth += columnWidth;
        }

        Colors = _backingStore;
        ViewWidth = currentWidth;
    }
}

The last piece of the puzzle is the XAML – in order to properly size the height, we need the actual height of the GridView itself, so the code behind hooks the SizeChanged event on the GridView and then passes the newly calculated size onto the MainViewModel:

private void OnPanelSizeChanged(object sender, Windows.UI.Xaml.SizeChangedEventArgs e)
{
    // Populate DC after first resize so we don't see small-ish items on first render.
    if (DataContext == null)
    {
        DataContext = new MainViewModel();
    }

    // Set the new actual height
    MainViewModel vm = (MainViewModel) DataContext;
    vm.ViewHeight = e.NewSize.Height;
}

We also need to respect the Canvas.Left and Canvas.Top properties – this would normally be done in an ItemContainerStyle, but unfortunately setting attached properties is not currently supported. To compensate for this, we override the GridView and set our properties onto each ItemContainer in the PrepareContainerForOverride method:

/// <summary>
/// This is here just to create a binding for the Height/Width on the GridViewItem.
/// WinRT currently doesn't support attached properties in Style setters.
/// </summary>
public class VariableSizedGridView : GridView
{
    protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
    {
        BindingOperations.SetBinding(element, Canvas.LeftProperty, new Binding { Path = new PropertyPath("Left") });
        BindingOperations.SetBinding(element, Canvas.TopProperty, new Binding { Path = new PropertyPath("Top") });
        BindingOperations.SetBinding(element, WidthProperty, new Binding { Path = new PropertyPath("Width") });
        BindingOperations.SetBinding(element, HeightProperty, new Binding { Path = new PropertyPath("Height") });

        base.PrepareContainerForItemOverride(element, item);
    }
}

And, of course we replace the panel for the derived GridView with a Canvas:

<differentSizedTiles:VariableSizedGridView ItemsSource="{Binding Colors}" Grid.Column="1" Grid.Row="1">
            
    <GridView.ItemContainerStyle>
        <Style TargetType="GridViewItem">
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
        </Style>
    </GridView.ItemContainerStyle>
            
    <GridView.ItemsPanel>
        <ItemsPanelTemplate>
            <Canvas SizeChanged="OnPanelSizeChanged" Width="{Binding ViewWidth}" />
        </ItemsPanelTemplate>
    </GridView.ItemsPanel> 
            
    <GridView.ItemTemplate>
        <DataTemplate>
            <Grid Margin="5" ToolTipService.ToolTip="{Binding}">
                <Rectangle Fill="{Binding Color}" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
                <Border Background="#30000000" VerticalAlignment="Top" HorizontalAlignment="Stretch" Height="40">
                    <TextBlock Text="{Binding}" Margin="10" Style="{StaticResource ItemTextStyle}" />
                </Border>
            </Grid>
        </DataTemplate>
    </GridView.ItemTemplate>
</differentSizedTiles:VariableSizedGridView>

Voila! Note that we still don’t have UI virtualization – it turns out that you currently cannot create a custom virtualized panel, the support isn’t exposed yet in WinRT. But even still, the performance is easily 100x better than the VariableSizeGridPanel. The code is slightly more complex, but not overly so. Here’s the final project if you want to play with it yourself. Have fun!

INotifyPropertyChanged in .NET 4.5

Implementing INotifyPropertyChanged in your XAML-based application has always been a point of hot debate. To date there are a variety of techniques – from the original (and fastest) “magic” string indicating the property name to the much slower, but compiler-checked Lambda expression tree implementation which provides refactoring safety. Both styles are included in my MVVM library (http://mvvmhelpers.codeplex.com). Trying to keep the performance of a raw string-based approach, but get the compile-time safety of the expression tree approach has been the goal of many WPF and Silverlight devs for the past few years. We’re getting closer…

.NET 4.5 (included in VS11 beta this week) brings a new option to the table in the form of the new [CallerMemberName] attribute. I saw this in Ander’s talk at //BUILD last year and immediately thought of INotifyPropertyChanged. Essentially, this attribute is applied to an input parameter on a method and the CLR will supply the calling method name as the parameter’s value. As an example, here is a sample INotifyPropertyChanged implementation using this new feature:

public class Person : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get { return _name; }

        set
        {
            if (_name != value)
            {
                _name = value;
                RaisePropertyChanged(); // note no parameter here!
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
}

Stopping in the debugger, you can see the value of the propertyName parameter:

The performance (at least of .NET 4.5 beta) is in between the unsafe magic string approach and the nice lambda approach – but this is perfectly refactor safe so it’s a nice new way to improve the safety of our code while getting closer to the performance of magic strings with our property change notifications.

This solution also provides for the “all properties have changed” notification by supplying the string – or passing null as the parameter.  If you specifically provide a parameter, then it overrides the <code>[CallerMemberName]</code> attribute and you get that string instead.  So, to raise an “all properties have changed” notification you could do this:

   RaisePropertyChanged("");
    // or
   RaisePropertyChanged(null);

and to raise a different property altogether you can just pass the magic string as you always have -

  // Callback from some long-running operation
  void OnCalculateSomeValueCompleted()
  {
     RaisePropertyChanged("CalculatedValue"); 
  }

It’s not the perfect solution however – as you can see above, we still have to use field-backed properties with this approach.  It would be so much nicer to have some compiler support here which calls the <code>RaisePropertyChanged</code> method from an auto-property.  This is done by some frameworks today using an AOP approach, but I’d like to see it with the native toolset.

This is a good step in the right direction though – thanks MSFT!

[EDIT: interestingly enough, I noticed that the latest MSDN example of INotifyPropertyChanged uses this exact approach – see here: http://msdn.microsoft.com/en-us/library/ms229614(v=vs.110).aspx

Dot-plotting with .NET Bio

One of the most common analysis done with genetic sequences is a dot-plot.  This is where we plot two sequences against each other – in the X and Y direction to get a sense of the similarity between them.  The dot-plot provides a simple, visual tool which can quickly identify consensus between the sequences.  While it was originally developed for the genetic field, the actual concept can be applied to any style of data – allowing professors to detect plagiarism for example.

.NET Bio doesn’t provide any direct support for dot-plots, but it’s fairly easy to do.  In this post,  we will build a simple dot-plot program to compare two sequences (or a sequence against itself), and then we will enhance it with sliding windows to reduce the noise often produced due to the low number of symbols being compared (A/T/C/G).

To start with, we will use a WPF application – since I’d like to take advantage of the Model-View-ViewModel pattern, I am going to include my library of helpers (http://mvvmhelpers.codeplex.com) but any MVVM helper library or routines would work here.  You can get this from NuGet if you install the NuGet package manager into Visual Studio 2010.

We will also use .NET Bio (http://bio.codeplex.com), the open-source bioinformatics library from Microsoft Research.  This library contains the core classes we will need to load, parse and interpret sequence data.

Introduction to Dot-Plots

The algorithm behind dot-plots is actually quite simple.  We will take the first sequence of data and lay it down on the X axis of our graph.  We will then take the second sequence and lay it along the Y-axis.  Then, we fill in the actual plot by comparing each coordinate position.  Where the X and Y are the same, we fill in that cell with a dot – where they are different we leave it blank.  As an example, consider the following data:

   T G C C T G G C G G C C G T A G C G C G G T G G T C C C A C
x       x                 x               x     x
G    x       x x   x x     x     x   x   x x   x x
C      x x       x     x x         x   x             x x x   x

When you compare the same sequence against itself you will see a diagonal line produced in the data where X == Y for each position.

In our program, once we load the two sequences, we will generate a byte array of matches.  As a simplistic example, consider the following code which takes two sequences (_sequences[0] and _sequences[1]) and generates a byte[] of 0×00 and 0xff:

private void CalculateDataPlot()
{
    const byte ON = 0xff;
    const byte OFF = 0x00;

    long width = _sequences[0].Count;
    long height = _sequences[1].Count;

    _plotData = new byte[height,width];

    Parallel.For(0, height, row =>
    {
        for (long column = 0; column < width; column++)
        {
            _plotData[row,column] = _sequences[0][column] == _sequences[1][row] ? ON : OFF;
        }
    });

    OnPropertyChanged(() => PlotData);
}

We can then easily take this produced data and data bind it to an Image control in WPF using a ValueConverter to create a new BitmapSource:

public class ByteArrayToImageConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter,
               System.Globalization.CultureInfo culture)
    {
        byte[,] values = value as byte[,];
        int height = values.GetLength(0);
        int width = values.GetLength(1);

        byte[] buffer = new byte[height*width];

        int i = 0;
        for (int row = 0; row < height; row++)
        {
           for (int col = 0; col < width; col++)
           {
              buffer[i++] = values[row, col];
           }
       }
       return BitmapSource.Create(width, height, 96, 96,
                     PixelFormats.Gray8, null, buffer, width);
   }

    public object ConvertBack(object value, Type targetType,
            object parameter, System.Globalization.CultureInfo culture)
    {
       throw new NotImplementedException();
    }
}

Loading a very simple sequence and comparing it against itself reveals the following image:

image

Notice the heavy amount of noise in the produced image?  The problem is we have a ton of random matches – in fact we have a probability of a 1/4 (25%) match given an alphabet of 4 characters!  This background noise is completely uninteresting in the data analysis, in fact it’s downright distracting to what we’d like to see.  To remove/reduce this noise, what we need to do is apply a filter to the data by forcing the size of the window required to produce a dot to be larger than it’s current value (1).

We’ll do that next week – stay tuned!

Here’s the 1st draft of the code — Sequence Dot Plot Part 1