.NET

Use a DataBound Smiley Face for Super-Easy Data Comprehension

Posted on Updated on

Humans can understand a smile in a heartbeat, but they need to think to parse a number. You can deal with that by displaying your data with smiley faces. Result: you will put a smile on your users’ faces, making their data easy to understand. By doing so, you’ll reduce your app’s overall costs, because training costs will be lower. Also, your users will get their work done faster when they can understand their data rapidly. For some apps, that speed can make the difference between profit or loss, such as apps used in fast-paced financial markets. If your company is work a meritocracy, you will be rewarded when your reduce costs for your company!

Screen Shot Showing Data-bound SmileyFac
This app analyzes job skills, such as C# or WPF, from ads posted on Stack Overflow. The jobs that have been advertised the longest get a smile, so do jobs that require few other skills. Why? Because, when the job is filled, the ad is removed, so the jobs left, the oldest, are for skills that are rare or in demand (generally speaking). Likewise, some jobs require a whole set of skills, but skills that employers desperately want may be advertised all by themselves, because they are hard to find. Good news for us: if when employers seek hard-to-find skills, they have incentive to pay well and treat you better! So, whatever WPA, WFP and TCL (top 3 rows above) are, they might pay better because of supply and demand. Smile if you know either skill!
Three Smiles
Enlarged view makes it easier to see the differences between the smile sizes.

What We Will Use to Build Our Data-Bound Smiley Face

  1. A WPF UserControl
  2. WPF Geometry Drawing, including
    1. EllipseGeometry (to draw the eyes and the face)
    2. Geometry Path Markup Strings – to draw the smile
  3. DependencyProperty – we add one to our UserControl to expose our new property ‘SmilePct’
  4. DataBinding – I’ll share a real pain-saver that will help you bind UserControls in DataGrids
  5. DataGridTemplateColumn – to host our SmileyFace in our grid

Get Started: Build Your UserControl

Hopefully you already know how to add a UserControl to your project (right-click your project in Solution Explorer, choose, ‘Add’, then pick ‘UserControl’). We will build a user control that has an Image for its XAML (no grid or StackPanel needed). We will draw 3 different parts in our image:

  1. The Face
  2. The Smile (data-bound)
  3. The Eyes
Screen-shot: user control XAML
Skeleton of the UserControl, whose XAML consists of a single Image. By using a DrawingGroup, we can draw three parts in the same Image: 1) The yellow face, 2) The Smile, and 3) The Eyes. Each separate part will be an individual GeometryDrasing. What you see here is just the bare-bones; we will ad the rest immediately below.

XAML for the Face

For the face, we will use a simple circle (actually an ellipse, but you probably know that a circle is merely a special case of an ellipse) with a gradient background.

<!-- The yellow face -->
<GeometryDrawing>
    <GeometryDrawing.Geometry>
        <!-- Draw the circle, which will represent the face -->
        <EllipseGeometry RadiusX="12.5" RadiusY="12.5" Center="6.25, 6.25"  />
    </GeometryDrawing.Geometry>
    <GeometryDrawing.Brush>
        <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
            <GradientStop Color="Gold" Offset="0"/>
            <GradientStop Color="Yellow" Offset="1"/>
        </LinearGradientBrush>
    </GeometryDrawing.Brush>
</GeometryDrawing>

To specify an ellipse, we describe the 1) size and shape using the RadiusX and RadiusY, plus 2) the position using the Center, which is described in Cartesian Coordinates (with the origin in the upper left corner of our Image). So, our face will be 25 pixels high (i.e. double the radius) and 25 pixels wide (double the RadiusX). Since RadiusX and RadiusY are equal, we will have a circle.

XAML for the Smiley

For the smile, we will use a string representation of the drawing to draw an ArcSegment. If you remember your geometry, or if you like to eat pies or pizza, you should already know that the ArcSegment is just the line represented by pizza crust. Basically a chunk of curve ripped out of a circle or, in the general case, an ellipse. We will build the geometry string in code; a sample geometry string looks like this: “M 0,10   A 10,25  0 0 0 12.5,10   Z”. I will explain how they work shortly; first, let’s look at the smiley XAML:

 <!-- The Smile, which is the only variable part-->
≶!-- The data binding will get the geometry from our code behind -->
 <GeometryDrawing Brush="White" Geometry="{Binding GeometryString}">
     <GeometryDrawing.Pen>
         <Pen Brush="RosyBrown" Thickness="1" />
     </GeometryDrawing.Pen>
 </GeometryDrawing>

It looks like not much is happening; that is because all the work is done via the Geometry property, which is bound to our code-behind. You can see the white brush, which is used for filling-in the teeth, and the pen (RosyBrown) which draws the lips. The shape of the lips is controlled via data binding, using a class property which I set in code. I will explain the Geometry string after explaining the XAML for the eyes. One further point: until now, I have not mentioned the data source I am binding to; in this case, I am binding to my own code-behind. I omitted that code until now (for clarity). To use your own code-behind for data binding, simply use the markup shown here to declare your UserControl:

<UserControl x:Class="CountJobTags.DataBoundSmiley"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             mc:Ignorable="d" 
	     <!-- The following tells WFP to do all binding using our own code-behind as the source -->
             DataContext="{Binding RelativeSource={RelativeSource Self}}"
             d:DesignHeight="300" d:DesignWidth="300">

 XAML for the Eyes

For the eyes, we will draw two ellipses. They are similar to the face; their RadiusY is slightly larger than their RadiusX, to make them taller than wide, and they user different colors than the face.

<!-- The eyes-->
<GeometryDrawing Brush="DarkBlue">
    <GeometryDrawing.Pen>
        <Pen Brush="White" Thickness="1.5" />
    </GeometryDrawing.Pen>
    <GeometryDrawing.Geometry>
        <GeometryGroup>
            <!-- Draw 2 ellipses, each slightly taller than wide, for the eyes -->
            <!-- Left eye-->
            <EllipseGeometry RadiusX="2" RadiusY="2.5" Center="2,5" />
            <!-- Right eye-->
            <EllipseGeometry RadiusX="2" RadiusY="2.5" Center="10.5, 5" />
        </GeometryGroup>
    </GeometryDrawing.Geometry>
</GeometryDrawing>

 Now, for the UserControl Code-Behind

The code-behind has a simple structure: just two properties:

  1. The GeometryString property, which tells WPF how to draw the smile, and
  2. The SmilePct property, which allows the outside world to control the size of our grin. 100% → big smile, while 0% → straight face

You might have noticed from my screen shots that my face never frowns, it just varies from a straight line to a big smile. I did that because, for one reason, it is a little easier, and also because I don’t want any frowns in my apps!

DependencyProperties

OK, I only have two properties, but you should make them be special DependencyProperty instances, because that is what works best with UserControls. DependencyProperties are similar to INotifyPropertyChanged properties, but designed for special situations like UserControls, etc. Here’s a quick tip: Visual Studio will help you stub-out a DependencyProperty if you type the shortcut ‘propdp‘ and hit the tab key. For details, take a look at my Visual Studio Quick Tip on the Snippet Manager. Here’s what my two properties look like:

private static string NO_SMILE = "M 5,12.5 A 10,0 0 0 0 7.5, 12.5 Z";

public string GeometryString {
    get { return (string)GetValue(GeometryStringProperty); }
    set { SetValue(GeometryStringProperty, value); }
}

//Windows stores the property value (for GeometrySttring) on your behalf, so you don't
//declare any variable to hold the value
public static readonly DependencyProperty GeometryStringProperty =
    DependencyProperty.Register("GeometryString", typeof(string), 
	typeof(DataBoundSmiley), new PropertyMetadata(NO_SMILE));


public double SmilePct {
    get { return (double)GetValue(SmilePctProperty); }
    set { SetValue(SmilePctProperty, value); }
}

//Note the callback referenced below, 'OnSmileyPctChanged'
public static readonly DependencyProperty SmilePctProperty =
    DependencyProperty.Register("SmilePct", typeof(double), 
	typeof(DataBoundSmiley), new PropertyMetadata(0.0, OnSmileyPctChanged));	

 Where’s the Logic?

I deliberately skipped the complicated part, so that I could emphasize the fact that I only have two properties in my code-behind. All the work happens when the SmilePct is set to a new value, which causes the callback method ‘OnSmileyPctChanged‘ to be invoked. That is where we assign the value for our GeometryString. The geometry string will vary between these two extremes, which I will explain shortly:

  • Big Smile  = “M 0,10   A 10,25  0 0 0 12.5,10   Z”;
  • No Smile   = “M 5,12.5 A 10,0   0 0 0 7.5, 12.5 Z”;

Geometry Path String Explanation:

  • “M 0,10” means start the drawing at the coordinates (0,10). “M 5,12” means start the drawing at coordinates (5,12.5)
  • “A 10,25  0 0 0 12.5,10   Z” defines an ArcSegment, where
    • “A” means start the arc
    • 10,25” means RadiusX =10,RadiusY =25
    • 0 0 0” means: (first zero) rotate 0 degrees; (second zero) IsLargeArc = false; (third zero) means Clockwise = false
    • 12.5,10″ means finish the arc at coordinates (12.5,10)
    • Z” means close the arc, i.e. draw a line from the end point to the start point, which, for us, represents the top lip

Besides ArcSegments, you can draw LineSegments, BezierSegments and QuadraticBezierSegments. You can read more about them here: https://msdn.microsoft.com/en-us/library/ms752293(v=vs.110).aspx. So, basically, my method ‘OnSmileyPctChanged’ serves to build a string like either 1) the big smile string listed above, 2) the no smile string, or 3) some arc segment intermediate between them. I’ll list the code here, but leave it to you to figure-out the algebraic computations involved. Remember, my callback is invoked when the SmilePct property is set.

public static void OnSmileyPctChanged(object sender, DependencyPropertyChangedEventArgs e) {
    double theVal = (double)e.NewValue;
    //protect against bad data:
    if (theVal < 0)
        theVal = 0.0;
    else if (theVal > 1.0)
        theVal = 1.0;

    double xInit = 5 - (5.0 * theVal);
    double yInit = 12.5 - (2.5 * theVal);
    double pctHappy = (25 * theVal);
    double xTerm = 7.5 + (5.0 * theVal);
    double yTerm = 12.5 - (2.5 * theVal);
    DataBoundSmiley theInstance = (DataBoundSmiley)sender;
    theInstance.GeometryString = string.Format("M {0}, {1} A 10,{2} 0 0 0 {3},{4} Z",
                                               xInit, yInit, pctHappy, xTerm, yTerm);
}

Final notes on the code-behind:  the input parameter ‘sender‘  represents our UserControl; ‘e‘ is the event args, containing the NewValue (for SmilePct) and other info. Since the method is static (required by WPF), we need to set the value of the GeometryString on the specific instance of the control which is identified by the input parameter ‘sender’.

Code-Behind Summary

OK, at this point, I’ve shown you the code to create the UserControl, which is basically just a drawing with three ‘sub’ GeometryDrawing elements. We use ellipses for the face and eyes, and the smile is an ArcSegment which I bind to a DependencyProperty in my code-behind. The property ‘GeometryString’ is set in my method ‘OnSmileyPctChanged’; in that method,  I use some algebra to define the ArcSegment corresponding to a big smile for high value of SmileyPct. All told, the control consists of

  • 54 lines of XAML, and
  • 60 lines of code

Using the Data-Bound Smiley in a DataGrid

I won’t talk about DataGrid basics here, suffice it to say that I will add a template column to my DataGrid to host my smiley UserControl. Actually, I want the single column to display a smiley face and a numeric value, which is easy if I embed a grid inside my template. Here’s the XAML, which I have simplified to only display the grid and the template column:

<DataGrid AutoGenerateColumns="False" Name="grdCountsByTag" IsReadOnly="True"  >
    <DataGrid.Columns>
        <!-- Other columns omitted for brevity. Define a template column here: -->
	<DataGridTemplateColumn Header="Avg. Age In Hours" CanUserSort="True" SortMemberPath="AvgAgeInHours">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Grid>
                        <!-- Textblock holds the number -->
                        <TextBlock Text="{Binding AvgAgeInHours, StringFormat=N2}" />
                        <!--Now the smilley; note the data binding, which was tricky -->
                        <local:DataBoundSmiley Grid.Column="1" 
                                               SmilePct="{Binding DataContext.AvgJobAgePct, 
                                                          RelativeSource={RelativeSource AncestorType=DataGridRow}}" />
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition />
                            <ColumnDefinition Width="auto" />
                        </Grid.ColumnDefinitions>
                    </Grid>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

Notes:

The prefix ‘local’ is an XMLNS definition which we place at the top of our form, like this:

<Window x:Class="CountJobTags.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CountJobTags"
        Title="Analyze Job Skills" Height="750" Width="705"
        WindowStartupLocation="CenterScreen" >

The namespace declaration allows us to reference classes from our own project in the XAML. The TextBlock is bound to a separate (but related) column: AvgAgeInHours. The Smiley control is bound to a field named ‘AvgJobAgePct’. The first, AvgAgeInHours, varies between 0 and 672 (usually), while AvgJobAgePct varies between 0 and 1; the two are inversely proportional. The data binding expression also bears notice, as I spent almost as much time on this as the rest of the code. It was a major source of frustration! Some key points:

  • A normal control (such as my TextBlock) binds directly to the same data source as the grid
  • Maddeningly, custom controls do not, their data source is, AFAIK, themselves
  • Which is why I needed to use the RelativeSource syntax to find the data source for the Grid Row hosting our control, i.e.
    RelativeSource={RelativeSource AncestorType=DataGridRow}
  • The DataContex syntax (e.g. ‘DataContext.AvgJobAgePct’) is used to avoid binding to properties of the Grid Row, such as width/height, and instead goes for the data source used to display the row

Summary

The smiley control quickly conveys meaning to your users, making their lives easier. A UserControl is the best way to build a re-usable container to display your data – without it, you would not be able to display smileys for two separate columns. The UserControl I built uses an Image containing a GeometryGroup which, in turn, holds three GeometryDrawings (face, eyes and smile). The Smile is defined in my control’s code-behind as a DependencyProperty; I build it using the syntax for the WPF Path Markup. Specifically, I use it to draw an ArcSegment, whose curve and endpoints vary according to the SmilePct. If you want your users to easily comprehend your data, I recommend you use my data-bound smiley, because users recognize faces with little mental effort. To get download code, you can go to my open source project on CodePlex: http://visualizejobskills.codeplex.com/

Make Your Data Graphical in WPF

Posted on Updated on

Data Visualization  and User Experience (UX) is very important in making your apps easy to use. If your apps are easy to use, they will be cheaper for your employer, because users will require less training and grasp the data faster. Hopefully, that will reflect positively on you too!. In this blog post, I will show a simple way to display a bar graph inside your grid to represent data.

Screen Shot Shows Bar Chart in Grid
With only a little bit of work, I was able to display my data graphically. The column ‘% Allowing Remote’ is essentially a bar chart that is much easier to read than a number. In applications where users make rapid decisions based on this data, that ease of understanding may be crucial! For example, trading applications, where quickly understanding the data allows traders to beat the competition.

The Basic Ingredients

To make this work, we will use:

  • Data Converter which allows the UI to convert a percentage value to a bar-graph width
  • DataTemplateColumn in the grid to display the bar graph
  • Rectangle, with variable width and colored background, to represent the value. Bind your rectangle width to the value
  • Textblock with transparent background to display the numeric value

The Converter

If you work with WPF, you already know that converters are used to bridge the gap between your data and the UI. Your converter will implement the interface IValueConverter; that will allow you to add it as a resource to your page. Basically, you write a bit of code in a simple class, add it as a resource to your page, then reference it in your data binding. Here is the code to write the Converter:

using System;
using System.Windows;
using System.Windows.Data;

namespace CountJobTags {
    public class Pct2WidthConverter : IValueConverter {
        public object Convert(object value, 
                             Type targetType, 
                             object parameter, 
                             System.Globalization.CultureInfo culture) {
            //'value' is PctAllowingRemote'
            if (value is double) {
            //Result will be int between 0 and 100: the width of the rectangle
                return (int)(100 * (double)value);
            }
            return 0;
        }

        //ConvertBack is used for read-write, this is readonly
        public object ConvertBack(object value, 
                                  Type targetType, 
                                  object parameter, 
                                  System.Globalization.CultureInfo culture) {
            return DependencyProperty.UnsetValue;
        }
    }
}

Your UI calls your converter for the PctAllowingRemote value in every grid row. The parameter ‘value’ holds what we bind to in the grid. Don’t worry, this will make more sense shortly.

Reference the Converter in your XAML

Once we have the code class to convert between our value (PctAllowingRemote) and the rectangle width, we need to reference the converter class in our XAML. To do so, we will need:

  • Resource
  • XMLNS reference to the class namesapce in our XAML, basically a shortcut prefix

Here’s the XAML from the top of my window where I set-up the XMLNS reference (XMLNS == XML NameSpace):

<Window x:Class="CountJobTags.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:CountJobTags"
        Title="Analyze Job Tags" Height="750" Width="705"
        MinHeight="300" MinWidth="400"
        FocusManager.FocusedElement="{Binding ElementName=btnFetch}"
        DataContext="{Binding RelativeSource={RelativeSource Self}}"
        WindowStartupLocation="CenterScreen" >

Basically, the highlighted code allows me to reference my own code inside the markup, using the prefix ‘local’ in front of any class names I need. ‘CountJobTags’ is the namespace that my class lives in. Relax: the Intellisense will help you write this code if you just type ‘xmlns:’ and pause.

Now, let’s use the prefix ‘Local’ to reference my converter as a resource. We enter the XAML below somewhere on our page. Of course, there are other ways, this is the most straighforward. We’re almost there!

<Window.Resources>
    <!-- Converts percentage to an int between 0 and 100, suitable for binding to a rectangle width to represent a bar graph -->
    <local:Pct2WidthConverter x:Key="widthConverter" />
</Window.Resources>

 Define a DataGridTempateDataColumn To Host The Bar

At this point, we have a converter and a means to reference it in our page. Now we need a special column in our grid that will host a Rectangle representing the value as its width. Here’s the simplified DataGrid with our template column, plus another column for comparison:

<DataGrid AutoGenerateColumns="False" Name="grdCountsByTag" IsReadOnly="True" >
    <DataGrid.Columns>
	   
        <!-- Normal column for comparison -->
        <DataGridTextColumn Header="Avg. Age In Hours"      
	    Binding="{Binding AvgAgeInHours, StringFormat=N2}" />

        <!-- Template holds rectangle, with variable width,
         and a Textblock for the text -->				
        <DataGridTemplateColumn Header="%Allowing Remote" 
			CanUserSort="True" SortMemberPath="PctAllowingRemote">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <Border Width="104" Height="20" >
                        <!-- Grid allows us to put 2 controls -->
                        <Grid>
                 <!--Rectangle has its width bound to the 
                 value we display, using the converter! -->
                            <Rectangle Height="18" HorizontalAlignment="Left" 
					VerticalAlignment="Center" Fill="DarkBlue" 
					Margin="2 0 2 0"
                                Width="{Binding PctAllowingRemote, 
					Converter={StaticResource widthConverter}}" />
                         <!-- Display the text; note transparent background color for Textblock
                         Color is chosen to be visible with either light or dark background -->
                            <TextBlock Background="Transparent" 
					Foreground="BurlyWood" HorizontalAlignment="Center" 
					Text="{Binding PctAllowingRemote, StringFormat=P}" />
                        </Grid>
                    </Border>
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>                                
        <DataGridTextColumn Header="Avg. # Related Skills"  
		Binding="{Binding AvgNumRelatedSkills, StringFormat=N2}" />
    </DataGrid.Columns>
</DataGrid>

The XAML above represents the simplified data grid with a normal column for comparison, and a template column which holds the bar. The template holds two controls, a Rectangle with variable width and a Textblock to display the text value. Important: note that both controls are bound to the same value, ‘PctAllowingRemote. The rectangle binds its width to the that value, using the converter we defined above, while the Textblock binds its text.

A couple key points:

  • You can place any kind of control in a template column
  • Normally you can only have a single direct child control; I used a layout grid (not a DataGrid) as the direct child and the grid will allow multiple child controls
  • By giving the Textblock a transparent background, it will appear on top of the rectangle
  • The text color is not super nice, but I have little choice because it must be visible with either a light or dark background
  • Normal columns allow sorting by default; but note that I had to specifically allow sorting (CanUserSort=”true”) and specify the column to use (please refer to the XAML for details.)

Bind Your DataGrid to an IEnumerable

I bound my entire grid to a List<TagAndCount> in code. Hopefully you already grasp that TagAndCount is a class and each row in the grid represents an instance of that class. Obviously, the class has properties that correspond to the grid columns, such as ‘PctAllowingRemote’. Here’s the code to bind it:

List<TagAndCount> tagList);
//...Write code to build the list, then bind:
grdCountsByTag.ItemsSource = tagList;

 Summary

WPF gives you a lot of flexibility on how to display data. You should make your data easy to understand using graphical techniques; that reduces training costs and improves comprehension of your data. Your users will thank you for making the data easier to use!

We displayed our data using a rectangle whose width is bound to the data we are displaying. The rectangle was bound using a reference to a converter class we wrote, which converted a percentage value into a different value between 0 and 100. The rectangle was displayed in DataGridTemplateColumn.

Get the Code

I already hosted this project on Codeplex. Occasionally I update that site and add features, such as my new bar-chart column. You can download the entire project or seem more of the code on line. The project is available here: http://visualizejobskills.codeplex.com/

WPF – Animate Textboxes to Highlight Bad Data

Posted on Updated on

WPF makes extremely good UIs (i.e. easy to use and attactive), but most programmers don’t take advantage of the power at their fingertips. One common scenario is providing immediate feedback when your users mess-up. I like to know immediately, not when I try to click the button to submit. Because I hate it when I don’t realize I made a mistake until long after the fact!

Screen shot shows invalid data entry triggering a border animation. The border is red with a moving color gradient.
Screen shot shows invalid data entry triggering a border animation. The border is red with a moving color gradient.

The Technique

  • Set-up validation for multiple textboxes with the same code
    • Using delegates to reduce your code!
  • Build a border animation
  • Using a gradient
  • Your gradient will use a moving middle stop, generating something like a wiping effect
  • Every time the textbox change event fires, call your validation on users’ text;
  • If bad, display your fancy animation, and set the tool tip and status bar message

The result looks (IMHO) pretty slick and is hard. I prefer it to the standard technique (IDataErrorInfo) for scenarios when I have several textboxes with the same validation rules, because it is less work overall.

The Fun Part – Animate Your Border!

public static void ReddenTextboxBorder(TextBox txt, MainWindow theMainWindow) {
    //Starting by defining 3 gradient stops; the middle one will move from left to right
    GradientStop stop1 = new GradientStop(Colors.Black, 0);
    GradientStop stop2 = new GradientStop(Colors.Red, 0);

    //Since we created the stop 'on-the-fly', we need to register the name to animate
    theMainWindow.RegisterName("stop2", stop2);
    GradientStop stop3 = new GradientStop(Colors.Black, 1);

    //We will use the brush for the border being animated, tell it all 3 stops:
    LinearGradientBrush gradBrush = new LinearGradientBrush(new GradientStopCollection { stop1, stop2, stop3 });
    txt.BorderBrush = gradBrush;

    //The animation will go from 1% to 99% over .3 second time period:
    DoubleAnimation ani = new DoubleAnimation(.1, .99, new Duration(TimeSpan.FromMilliseconds(300)));
    //When we hit the right border, bounce back to the left again:
    ani.AutoReverse = true;

    //Storyboard helps connect the animation parts
    Storyboard sb = new Storyboard();
    Storyboard.SetTargetName(ani, "stop2");
    Storyboard.SetTargetProperty(ani, new PropertyPath(GradientStop.OffsetProperty));
    sb.Children.Add(ani);

    //After the animation is don, set the border to pure red (no gradient)
    sb.Completed += delegate(object sndr, EventArgs evtArg) { txt.BorderBrush = new SolidColorBrush(Colors.Red); };

    sb.Begin(theMainWindow);
    //By unregistering the name, I release memory and become confident I can re-run without issues
    theMainWindow.UnregisterName("stop2");
}

At this point, we have a method to animate any textbox, so long as it inhabits our main form. It looks cool and tells the user they messed-up with minimal pain. Now, let’s hook-up several textboxes to use our new method:

Connect the Animation to Your Validation

private void SetUpRequiredFieldValidation()
{
    //An array of textboxes which must be populated before user 
    //can click the button to do some work
    TextBox[] _RequiredTextBoxes = new[] { txtName, 
                         txtAddress, 
                         txtCity, 
                         txtState, 
                         txtZip
                         };

    //Hook-up a TextChanged event for every textbox in the array; 
    foreach (TextBox tb in _RequiredTextBoxes)
    {
        //Dynamically declare an event to fire for each textbox using a delegate
        tb.TextChanged += delegate(object sender, TextChangedEventArgs e) {
            //'ValidIdentifier' (omitted for clarity) is my Regular Expression that checks
            //whether the textbox text is valid. You could substitue
            /your own validation logic here, such as 'String.IsNullOrWhitespace(tb.Text)'
            if (Utility.ValidIdentifier.IsMatch(tb.Text))
            {
                //Omitted for clarity - clear the color/tooltip/border thickness etc.
                ResetTextboxBorder(tb);
            }
            else 
            {
                tb.BorderThickness = new Thickness(3);
                ReddenTextboxBorder(tb, this);
                tb.ToolTip = "Invalid name";
                //Display some information in the status bar:
                stbMessage.Text = "Learn to type, user!";
            }
        };
    }
}

Here, I build an array containing all the textboxes I wish to validate. I then loop through them, and for each textbox, hook-up a TextChanged event. That event

  • Checks if the uers’ text is valid, if so
    • Clear any previous effects from the textbox
  • Otherwise, animate the border and set the tool tip

Summary

Animation makes your applications easier to use and less frustrating. More importantly, apps with animated feedback require less training. If you have a lot of users, training costs can be significant, so you are really cutting-down on the cost to run your app. Your user manager should love you when you save them costs! Maybe you will be recognized for writing superior code! BTW, you could do this in HTML/ASP or other web technologies, but not as slickly nor as easily! WPF makes vastly superior UIs!

Download the code!

NPR Puzzle Solved!

Posted on

What a blast to solve this one! Once in a while, everything works exactly right, and this was one of those fabulous times. My program ran the first time! (Which only happens a few times a year), plus I had all the right files on hand, and I didn’t need to fuss with any bad data. Bottom line: it took way longer to write this blog post than it took to solve the puzzle.

The challenge:

This week’s challenge comes from listener Smatt Read of Somerville, Mass. Actor Tom Arnold goes by two first names — Tom and Arnold, both male, of course. And actress Grace Kelly went by two first names — Grace and Kelly, both female. Name a famous living actress who goes by three first names, all of them traditionally considered male. The names are 5, 3 and 6 letters long, respectively.

The Solution

Screen shot showing the solution
Screen shot showing the solution

Techniques You Will Learn

  • Simple File IO
  • String manipulation
  • Binary search and generic list manipulation

The Code

private void btnSolve_Click(object sender, RoutedEventArgs e) {
    Mouse.OverrideCursor = Cursors.Wait;
    txtSolution.Clear();

    //Load the list of boy names into a sorted list
    List<string> boyNames = new List<string>();
    using (StreamReader sr = File.OpenText(BOY_NAME_FILE)) {
        //Read every line in the file
        while (sr.Peek() != -1) {
            string aLine = sr.ReadLine();
            //The name is the first thing on the line, and it is immediately followed by a space
            int p = aLine.IndexOf(' ');
            //Grab the name out of the line we just read:
            string aName = aLine.Substring(0, p);
            p = boyNames.BinarySearch(aName);
            if (p < 0) {
                //Binary search returns a negative number if not found, by inverting
                //the number, we get the index where the name belongs in the sort order
                boyNames.Insert(~p, aName);
            }
        }
    }

    //This folder contains a number of files, for with names 
    //like, for example, 'British_silent_film_actresses.txt'
    string[] actressFiles = Directory.GetFiles(ACTRESS_FOLDER);
    foreach (string fName in actressFiles.Where(f => f.IndexOf("actress") >= 0)) {
        //Open all the actress files and check each against the boy name list
        using (StreamReader sr = File.OpenText(fName)) {
            while (sr.Peek() != -1) {
                string aLine = sr.ReadLine();

                //build an array with each name filling a slot in that array
                string[] tokens = aLine.ToUpper().Split(' ');
                if (tokens.Length > 2) {
                    int matchCount = 0;
                    //Count how many names, for this actress, are found in the boy list:
                    foreach (string aName in tokens) {
                        int p = boyNames.BinarySearch(aName);
                        //Binary search is very fast and returns a non-negative number if found
                        if (p >= 0)
                            matchCount++;                                
                    }
                    //If we have at least 3 matches, we found a winner!
                    if (matchCount > 2) {
                        txtSolution.Text += aLine + "\n";
                    }
                }
            }
        }
    }
    Mouse.OverrideCursor = null;
}

Data Comments

I originally got the actress files from wikipedia http://en.wikipedia.org/wiki/Lists_of_actresses to solve a different puzzle. I believe I obtained the list of boy names from the census bureau a long time ago, but I can’t find the link any more.

Download the code (includes data files)!

Defensive Coding with Linq and Generic Methods

Posted on Updated on

Suppose you work with some off-shore programmers. Also suppose that those off-shore programmers write your BLL (Business Logic Layer) Code. Further, suppose those programmer constantly change your results without telling you. Finally, suppose they give you results in DataTable format, which is completely flexible and not strongly typed, thus making it hard to detect unannounced changes.

Given those assumptions, you’ve got a situation where they break your code all the time and  leave you to clean-up the mess. And that is the situation I will address in this post.

Not to slam off-shore programmers per se, but perhaps something about working in a different time zone, in a different culture, makes it more likely they will not understand your needs, even if those needs seem blindingly obvious to you! So, my attitude is, just do the best you can under the circumstances and hope the blame falls on the right shoulders. Defensive coding will help. Even if your teammates work in the cube next to you, that type of coding can help.

What You Will Learn

  1. How to use Linq (actually Lambda expressions) on DataTables to check for missing columns
  2. How to use Generic Methods to simplify your logic for extracting data out of a DataTable while checking for misnamed columns

Step One: Check if the Table Returned by the BLL Team has the Columns You Need

If the result set lacks columns we need, we need to log that problem. Also, we should try to work with the data we get and avoid completely crashing. Here is my short-and-sweet method to log missing columns and check how many desired data columns are present in the data we get from the BLL. Basically, I use the ‘Except’ method to compare one list (the expected columns list) against another list (the actual column list in the data table):

public int ColumnMatchCount(DataTable dtReturnTable,
                            List<string> expectedColumnNames,
                            string callingMethod)
{
    //Use the lambda expression 'Except' to determine which columns
    //are not present in the data table provided by BLL
    var unmatched = expectedColumnNames
        .Except(dtReturnTable.Columns.Cast<DataColumn>()
        .Select(c => c.ColumnName));
    foreach (string missingCol in unmatched) {
        //Log the problem column
        _Logger.Log(LogLevel.Error, callingMethod +
                    " - expected BLL to provide column '"
                    + missingCol
                    + "' in the ReturnTable, but it was not present.");
    }
    //Tell the caller how many columns match
    return expectedColumnNames.Count - unmatched.Count();
}

Key point: The data table has a columns collection we can compare using the Except method. Since DataTables are not quite the type of data that works with Linq, we use ‘Cast<DataColumn>() to make ti work. Because DataTables existed before Linq.

In my case, I will give my clients data if at all possible, i.e. if the BLL crew has given me at least one column that matches what they told me they would provide. I’ll provide some sample code shortly, but first, let’s look at my method to get the data out of the data table when the column I expect might not be there.

Step Two: Get Data from the DataTable  When a Column is Missing

If the BLL gave me the column I expected, no big deal (of course, I also want to handle possible null values). But, if the column I want is not even present, a default value should be used instead. The method below does that, and it works for any data type, whether string, int, DateTime, etc. Because it is written as a Generic Method, it can handle any data type you provide.

public T CopyValueFromTable<T>(DataRow dr, string columnName)
{
    T result = default(T);
    if (dr.Table.Columns.Contains(columnName) && ! dr.IsNull(columnName))
        result = (T)dr[columnName];
    return result;
}

The method takes a data row as input and examines that DataRow’s parent table.

    dr.Table

That table has a Columns collection, and we can check it to see if the column exists or not.

    if (dr.Table.Columns.Contains(columnName)

If the BLL crew remembered to give us the column we need, and it it is actually present and not null, then extract it.

dr[columnName]

If you understand Generic Methods, you will recognize that ‘T’ is the data type our caller wants us to use, so we convert the data column to type ‘T’. We cast it to type T using the parenthesis notation; remember that
‘T’ is a placeholder for any type, such as int, string, DateTime, etc.

    result = (T)dr[columnName];

The first line in my method ensures that an appropriate default value will be returned if no other choice is available, the ‘default’ method will give us an empty string, a zero, etc., depending on what type is represented by ‘T’:

    T result = default(T);

Putting it All Together

Screen shot shows my code handling unexpected missing column 'ServiceCenterID' and using a default value instead. The discrepancy was logged.
Screen shot shows my code handling unexpected missing column ‘ServiceCenterID’ and using a default value instead. The discrepancy was logged.
private void btnSimulateUnplanedChange_Click(object sender, RoutedEventArgs e) {
    BLL dataFetcher = new BLL();
    //Ask our simulated BLL to get some data, which will lack the column 'ServiceCenterID'
    DataTable ReturnTable = dataFetcher.UnannouncedChange_GetServiceCenters();
    List<string> expectedColumns = new List<string> { "Location", 
                                "LocationDescription", "ServiceCenter", "SCDescription" };
    List<InventoryResponse> response = new List<InventoryResponse>();


    //If at least one column name matckes, 
    if (ColumnMatchCount(ReturnTable, expectedColumns, "GetResults") > 1) {
        foreach (DataRow dr in ReturnTable.Rows) {
            InventoryResponse invResp = new InventoryResponse();
            invResp.ServiceCenterID = CopyValueFromTable<int>(dr, "ServiceCenterID");
            invResp.Location = CopyValueFromTable<string>(dr, "Location");
            invResp.SCDescription = CopyValueFromTable<string>(dr, "SCDescription");
            response.Add(invResp);
        }
        txtResults.Text = RjbUtilities.DebuggerUtil.ComplexObjectToString(response);
    } else {
        _Logger.Log(LogLevel.Error, "No column names match the expected values");
    }
}

Summary

Sometimes you can’t work with top-quality programmers and possibly they don’t understand the concept of their teammates depending on their code. If you can’t force them to grow-up and communicate, at least you can make sure your code logs the problem and does the best it can with what they give you.

I showed you one method ‘ColumnMatchCount’ that checks how many expected columns are present the results the BLL crew gives you. I showed you another method ‘CopyValueFromTable’ that will provide default values and avoid crashing if the BLL crew renamed a column without telling you.

If you write similar defensive code, you might be lucky and your managers will blame the appropriate people!

Download my sample code here.

Copying with AutoMapper and MemberwiseClone

Posted on Updated on

Copying and cloning is easy, if you know how. Sadly, I’m working on a project where my teammates write many lines of code to accomplish what I can do in just a few. Needless to say, they write tedious and error-prone code that tends to hide their important functionality. If you master a few concepts, you might get some recognition for your superior code, by writing less of that “copying code”!

Note: most of this is pretty straightforward and available elsewhere. However, if you are patient, I will show you how to use AutoMapper for data tables, a concept that I could not easily find on other sites. Besides being a bit tricky, using AutoMapper on tables saves a bunch of code. (Note: AutoMapper is open source and well established.)

Memberwise Clone

If you just want a copy of an object, use MemberwiseClone. Every class implements it by default. At work, one of my teammates has literally written dozens of lines of code to do what this does already; that seems like a big waste of time! (In case you read this, team member, fear not: I have not slammed you at work!)

Screen Shot - Memberwise Clone
Screen shot showing an address object being copied.

Sample Code: Memberwise Clone

public class Address {
    public string Line1 { get; set; }
    public string Line2 { get; set; }
    public string Line3 { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public string Country { get; set; }
    public int DeliveryZone { get; set; }
    public string ZipCode { get; set; }
    public float Latitude { get; set; }
    public float Longitude { get; set; }
    public List<Tenant> Tenants { get; set; }

    public Address Clone() {
        return (Address) this.MemberwiseClone();
    }
}
//Usage:
WCF.Address source= new WCF.Address{ City="Atlantis", ...};
WCF.Address dest = addr1.Clone();

Notes

  1. MemberwiseClone performs a “shallow clone”
  2. The new instance is not completely independent form the original
  3. For example, if I assign addr1.Tenants[0].Name = “Sally”, then addr2 gets its the change too for its first Tenant, i.e. it too is assigned the value “Sally”
  4. Essentially, the child objects are references to the same memory locations
  5. If you don’t want this, just implement ‘Clone’ for your child objects! In my example above, I would merely implement Clone on the Tenant class and make use of it in the Address Clone.

AutoMapper

AutoMapper is for when you have similar, not identical classes. AutoMapper:

  • Can be set-up with one line of code
  • Will copy similarly named properties with no additional input from you
  • Can handle dissimilar properties with just a small bit of work from you

One Typical Usage scenario:

  • Your DAL teammates use their own classes; they want you to fill them before they give you their results
  • You need to take the input you get form your WCF classes, copy it into corresponding DAL classes, then tell them to do the work
Simple use of AutoMapper. I realize you can find lots of documentation on this elsewhere, but I wanted to give some background before covering more a advanced scenario.
Simple use of AutoMapper. I realize you can find lots of documentation on this elsewhere, but I wanted to give some background before covering more a advanced scenario. Note that the value in property ‘Province’ is copied into a different property called ‘State’, and I set this up by specifying a ‘ForMember’  mapping (see below).

The Code

//Properties with different names must be mapped. All others are copied automatically.
Mapper.CreateMap<DAL.Address, WCF.Address>()
      .ForMember(m => m.State, opt => opt.MapFrom(s => s.Province));

//set-up the source
DAL.Address source = new DAL.Address { Line1 = "33 State Str.", Line2 = "#351", 
                        City = "Rome", Province = "NY", Country = "USA", 
                        DeliveryZone = 3, PostalCode = "11304" };
txtOriginal.Text = RjbUtilities.DebuggerUtil.ComplexObjectToString(source);

//Do the work!
WCF.Address dest = Mapper.Map<WCF.Address>(source);
txtResult.Text = RjbUtilities.DebuggerUtil.ComplexObjectToString(dest);

As you can see, AutoMapper automatically handles at least seven lines of code for you, thus allowing you to spend your attention on more challenging tasks. Now, let’s try something a bit trickier, mapping from DataTables.

Using AutoMapper to Extract Data From DataTables

For whatever reason, all the documentation and samples I found on line didn’t work or else didn’t help. After a few hours of trying variations, here’s a good way to do it. Note: if your DAL gives you DataTables, this can save even more lines of code, . You don’t need to write any loops, and you don’t need to check for nulls.

Before and after shot of a data table being copied to a list of Address objects.
Before and after shot of a data table being copied to a list of Address objects.

Here’s the Code

DataTable dt = BuildDummyDataTable();
txtOriginal.Text = DataTableToText(dt);
//Set-up the mapping; I could do it in just one line, except for the Province Column,
//which needs to go into a differently named property
Mapper.CreateMap<IDataReader, WCF.Address>()
       .ForMember(s => s.State, opt => opt.MapFrom(d  => d["Province"]));

//Do the work!
List<WCF.Address> addrLst = Mapper.Map<List<WCF.Address>>(dt.CreateDataReader());
txtResult.Text = RjbUtilities.DebuggerUtil.ComplexObjectToString(addrLst);

Basically, we set-up a mapping between a DataReader and an Address class, then create a DataReader from our DataTable and ask AutoMapper to handle the details. I don’t have to tell you that this saves a lot of work!

Other AutoMapper Features

AutoMapper provides a lot more features, such as null-handling, flattening and projection. I invite you to visit their site for additional info. AutoMapper

Summary

There are many scenarios under which you need to copy objects from one container to another. If you just need a shallow clone, use MemberwiseClone. If you need to copy into a different class, use AutoMapper. You can set-up AutoMapper to work with lists and data tables, which are very common scenarios. At my current gig, I use AutoMapper a lot for communicating with our DAL and for transforming objects to send/receive to other companies via WCF .

Needless to say, you will meet your deadlines faster and write cleaner code when you use these two techniques. When you use them, you can reduce big, long chunks of code into shorter ones. As a result, the non-trivial parts of your code are not buried in humdrum ‘copying code’.

Download: here’s my sample project.

 

NPR Puzzle Solved! 9-Letter City → Two

Posted on Updated on

Yippee-kai-yay! That was a super-fast solution.

What You will Learn

  • Simple file IO
  • Simple string manipulation
  • Simple WCF layout, design, and other techniques

The challenge:

This week’s challenge comes from listener Steve Baggish of Arlington, Mass. Think of a U.S. city whose name has nine letters. Remove three letters from the start of the name and three letters from the end. Only two will remain. How is this possible, and what city is it?

Link to the challenge
And here’s a screen shot of my solution:

Screen shot showing the solution to the NPR puzzle.
Screen shot showing the solution to the NPR puzzle.

In case you don’t get it, the middle 3 letters of ‘Fort Worth’ are ‘two‘.

The Algorithm

  1.  Loop through the file containing city names
  2. Convert each to lower case and remove spaces
  3. Take the substring representing the middle 3 characters
  4. If the result is ‘two’, ‘2’ or else has length 2, then we have a winner!

Here’s the short, sweet code:

private void btnSolve_Click(object sender, RoutedEventArgs e) {
    Mouse.OverrideCursor = Cursors.Wait;
    StringBuilder sb = new StringBuilder();

    //Open the file for reading:
    using (StreamReader sr = File.OpenText(CITY_FILE)) {
        //Loop until the end:
        while (sr.Peek() != -1) {
            string curLine = sr.ReadLine();
            //send the input to lowercase and remove spaces:
            string city = curLine
                         .ToLower()
                         .Replace(" ", "");
            //Only look at cities having length 9:
            if (city.Length == 9) {
                string candidate = city.Substring(3, 3);
                if (candidate == "two" || candidate == "2" || candidate.Length == 2)
                    sb.AppendFormat("Original city: '{0}'\nAfter removing first 3 and last 3: '{1}'\n", 
                                    curLine, city.Substring(3, 3));
            }
        }
    }
    lblResults.Visibility = txtResults.Visibility = System.Windows.Visibility.Visible;            
    txtResults.Text = sb.ToString();
    Mouse.OverrideCursor = null;
}

Comments

To be honest, I just got lucky with this one. I just wrote the code to chop-off the first 3 and last three and display it in a list. As it happens, the very first entry in my temporary results was the winner. Too bad there’s no way to profit on this one, as the reward divided by the effort was very favorable!

Als, I had the list of cities lying around from previous puzzle attempts, but I believe I originally downloaded it from wikipedia (after writing some code to clean-it-up. If you download my sample code, the file is included.

 Download the code!

Write a WCF Test App to Connect to Multiple URLs

Posted on

Scenario: you have deployed your WCF web service to multiple servers, including

  • Localhost
  • Dev server
  • Integration Server
  • Training server
  • etc.

It would be nice to connect and test to each server with the exact same code! Who wants to write a different app just to connect to a different server with the exact same service.

Screen shot showing a single app connecting to a different server, chosen from the combo box
Screen shot showing a single app connecting to a different server, chosen from the combo box

In the sample above, I get all the available URLs from my config file (in the section “system.serviceModel/Client”). This is convenient if you have established service references in the normal manner. However, it it not necessary to do this.

Part One: Establish a WCF Client/Proxy using a URL Provided at Run Time

We will take advantage of the constructor signature that accepts a URL and a contract. Obviously, the URL will vary according to which server we connect to! If all the servers use the same WSDL, we can use a single contract name; in this case, I use the one from my config file.

public static localInventorySvc.InventorySvcClient BuildClient(string serviceUrl) {
    localInventorySvc.InventorySvcClient result;

    //This is a binding from my config file; it is also possible to
    //construct one in code (but I don't need to)
    string contractName = "BasicHttpBinding_IInventorySvc";

    //The new client/proxy will connect to the URL provided to us:
    result = new localInventorySvc.InventorySvcClient(contractName, serviceUrl);
    return result;
}

At this point, we can just use our client like one we constructed any other way, such as this:

localInventorySvc.InventorySvcClient myClient = BuildClient(cboUrls.Text);
localInventorySvc.GetInventoryDataRequest myRequest = new localInventorySvc.GetInventoryDataRequest();
myClient.getInventoryData(myRequest);

I have simplified the code – I skipped providing the parameters for my request object, but that is rather trivial.

Part Two (Optional) Get URLs from your Config File

Every time you create a new service reference, your config file holds the details, including the URL. This is rather convenient. The only issue is figuring-out the proper syntax to access that data. If you include a using statement for “System.ServiceModel” in your code, you can retrieve a ClientSection object using the configuration manager.

private void Window_Loaded(object sender, RoutedEventArgs e) {
    //Iterate the endoints from the config file and add them to the combo box:
    List<string> allUris = new List<string>();
    ClientSection clientSection;
    //This is the tricky part:
    clientSection = (ClientSection) ConfigurationManager
                    .GetSection("system.serviceModel/client");
    if (clientSection != null) {
        foreach (ChannelEndpointElement ep in clientSection.Endpoints) {
            allUris.Add(((ChannelEndpointElement)ep).Address.AbsoluteUri);
        }
    }
    //Now that we have all the urls, display them in the combo box:
    cboUrls.ItemsSource = allUris;
    if (allUris.Count > 0)
        cboUrls.SelectedIndex = 0;
}

Config File

Here, you can see the two URLs which appear in my combo box; obviously you can add more when you add service references.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
    <system.serviceModel>
        <bindings>
          <wsHttpBinding>
            <binding name="BasicHttpBinding_IInventorySvc" />
            <binding name="BasicHttpBinding_IInventorySvc1" />
          </wsHttpBinding>
        </bindings>
        <client>
            <endpoint address="http://localhost:49830/InventorySvc.svc" 
                  binding="wsHttpBinding"
                  bindingConfiguration="BasicHttpBinding_IInventorySvc" 
                  contract="localInventorySvc.IInventorySvc"
                  name="wsHttpBinding_IInventorySvc" />
            <endpoint address="http://localhost/UniversalMessageProcessor/InventorySvc.svc"
                binding="wsHttpBinding" 
                bindingConfiguration="BasicHttpBinding_IInventorySvc1"
                contract="deployedInventorySvc.IInventorySvc" 
                name="wsHttpBinding_IInventorySvc1" />
        </client>
    </system.serviceModel>
</configuration>

 Download the code! Remember, you won’t have the same service references, so you will need to tweak the project to run it.

Visual Studio Quick Tip: Snippet Manager Writes Code for You!

Posted on Updated on

You can type less and meet your deadlines faster by using the snippet manager for boiler plate code, such as properties, try-catch blocks, etc. Plus, you look like a total expert when you blast-in your code with just a few keystrokes! Learn how by watching my video.

Video: Easily enter boiler plate code with Snippet Manager

Total time: 03:46

Video Quick Tips: Use Intellisense for Super Productivity

Posted on Updated on

Intellisense is a fantastic invention that, sadly, most programmers don’t take full advantage of. If you like to meet your deadlines, and impress your coworkers with your magical typing skills, take a quick look at these videos.

Intellisense quick tip #1 – Amp-up your productivity with Intellisense!

Total time: 01:39

Intellisense quick tip #2 – Method signatures made easy!

Total time: 02:04

Intellisense quick tip #3 – Different ‘pick keys’; using Intellisense to correct your typing

Total time: 02:30