Blog Archives

The Prototype Pattern – Techniques, Strategies and Patterns for Structuring JavaScript Code

Using the JavaScript Prototype Pattern

This is the 2nd post in a series on techniques, strategies and patterns for writing JavaScript code. In my previous post I introduced what I call “function spaghetti code” and explained some of the problems it introduces. I also talked about the impact of global variables and how closures add a much needed solution. In this post I’ll introduce the Prototype Pattern and show how it relies on built-in functionality in the JavaScript language.

I’ve worked through some of the patterns I’m covering in this series with my good friend John Papa over Skype and we’ve talked about pros and cons of different approaches. For example, he initially recommended defining multiple variables using a single var based on JSLint suggestions (that was covered in the previous post) and I agreed that it was a better approach than using var for every variable. It’s interesting how code evolves with feedback from multiple people. John and I have definitely come to enjoy working with a few different patterns and although the Prototype Pattern isn’t in my favorites list, I’ve always felt that it’s good to understand and know the different options out there. That’s why I decided to include it in this series.

The Prototype Pattern can be broken out into two main sections including a constructor section and a prototype section. Prototyping allows functions and properties to be associated with objects. However, instead of each object instance getting a copy of all functions/properties each time an object is created, only one set of functions/properties exists across all objects resulting in less memory consumption. In other words, functions and properties are defined once per prototype rather than once per object.

As a quick review, I showed the following code in a previous post. The code simply lists all functions directly with no encapsulation and defines several global variables. While the code works fine this way, I’ll examine how we can restructure it to follow the Prototype Pattern.

window.onload = function () {
    eqCtl = document.getElementById('eq');
    currNumberCtl = document.getElementById('currNumber');
};

var eqCtl,
    currNumberCtl,
    operator,
    operatorSet = false,
    equalsPressed = false,
    lastNumber = null;

function add(x,y) {
    return x + y;
}

function subtract(x, y) {
    return x - y;
}

function multiply(x, y) {
    return x * y;
}

function divide(x, y) {
    if (y == 0) {
        alert("Can't divide by 0");
        return 0;
    }
    return x / y;
}

function setVal(val) {
    currNumberCtl.innerHTML = val;
}

function setEquation(val) {
    eqCtl.innerHTML = val;
}

function clearNumbers() {
    lastNumber = null;
    equalsPressed = operatorSet = false;
    setVal('0');
    setEquation('');
}

function setOperator(newOperator) {
    if (newOperator == '=') {
        equalsPressed = true;
        calculate();
        setEquation('');
        return;
    }

    //Handle case where = was pressed
    //followed by an operator (+, -, *, /)
    if (!equalsPressed) calculate();
    equalsPressed = false;
    operator = newOperator;
    operatorSet = true;
    lastNumber = parseFloat(currNumberCtl.innerHTML);
    var eqText = (eqCtl.innerHTML == '') ?
        lastNumber + ' ' + operator + ' ' :
        eqCtl.innerHTML + ' ' + operator + ' ';
    setEquation(eqText);
}

function numberClick(e) {
    var button = (e.target) ? e.target : e.srcElement;
    if (operatorSet == true || currNumberCtl.innerHTML == '0') {
        setVal('');
        operatorSet = false;
    }
    setVal(currNumberCtl.innerHTML + button.innerHTML);
    setEquation(eqCtl.innerHTML + button.innerHTML);
}

function calculate() {
    if (!operator || lastNumber == null) return;
    var currNumber = parseFloat(currNumberCtl.innerHTML),
        newVal = 0;
    //eval() would've made this a whole lot simpler
    //but didn't want to use it in favor of a more
    //"robust" set of methods to demo patterns
    switch (operator) {
        case '+':
            newVal = add(lastNumber, currNumber);
            break;
        case '-':
            newVal = subtract(lastNumber, currNumber);
            break;
        case '*':
            newVal = multiply(lastNumber, currNumber);
            break;
        case '/':
            newVal = divide(lastNumber, currNumber);
            break;
    }
    setVal(newVal);
    lastNumber = newVal;
}

 

To start using the Prototype Pattern you need to first create a constructor as shown next. The constructor can accept one or more parameters and define any variables that the object needs. Note that the variables are scoped to the object rather than to the global scope.

var Calculator = function (tb, eq) {
    this.eqCtl = document.getElementById(eq);
    this.currNumberCtl = document.getElementById(tb);
    this.operator = null;
    this.operatorSet = false;
    this.equalsPressed = false;
    this.lastNumber = null;
};


Once the constructor is defined a prototype can be created using the prototype keyword. Although you can create a prototype for each function, it’s more convenient (and less typing) to take advantage of JSON-style syntax where the function name represents the JSON property name and the value represents the function. An example of defining two functions in a prototype is shown next. Notice that each function is separated with a comma just as you would separate properties defined in a normal JSON object. It’s officially called a JavaScript object literal, but if you’re familiar with JSON it uses the same standard syntax (thanks to Craig Stuntz for clarifying that):

Calculator.prototype = {

    add: function (x, y) {
        return x + y;
    },

    subtract: function (x, y) {
        return x - y;
    }
}


The original function-based calculator code shown earlier can be refactored to follow the Prototype Pattern as shown shown next. A prototype is created for the Calculator object and functions/properties are defined within the prototype using JavaScript object literal syntax.

Calculator.prototype = {

    add: function (x, y) {
        return x + y;
    },

    subtract: function (x, y) {
        return x - y;
    },

    multiply: function (x, y) {
        return x * y;
    },

    divide: function (x, y) {
        if (y == 0) {
            alert("Can't divide by 0");
        }
        return x / y;
    },

    setVal: function(val) {
        this.currNumberCtl.innerHTML = val;
    },

    setEquation: function (val) {
        this.eqCtl.innerHTML = val;
    },

    clearNumbers: function () {
        this.lastNumber = null;
        this.equalsPressed = this.operatorSet = false;
        this.setVal('0');
        this.setEquation('');
    },

    setOperator: function (newOperator) {
        if (newOperator == '=') {
            this.equalsPressed = true;
            this.calculate();
            this.setEquation('');
            return;
        }

        //Handle case where = was pressed
        //followed by an operator (+, -, *, /)
        if (!this.equalsPressed) this.calculate();
        this.equalsPressed = false;
        this.operator = newOperator;
        this.operatorSet = true;
        this.lastNumber = parseFloat(this.currNumberCtl.innerHTML);
        var eqText = (this.eqCtl.innerHTML == '') ?
            this.lastNumber + ' ' + this.operator + ' ' :
            this.eqCtl.innerHTML + ' ' + this.operator + ' ';
        this.setEquation(eqText);
    },

    numberClick: function () {
        var button = (event.target) ? event.target : event.srcElement;
        if (this.operatorSet == true || this.currNumberCtl.innerHTML == '0') {
            this.setVal('');
            this.operatorSet = false;
        }
        this.setVal(this.currNumberCtl.innerHTML + button.innerHTML);
        this.setEquation(this.eqCtl.innerHTML + button.innerHTML);
    },

    calculate: function () {
        if (!this.operator || this.lastNumber == null) return;
        var displayedNumber = parseFloat(this.currNumberCtl.innerHTML)
            newVal = 0;
        //eval() would've made this a whole lot simpler
        //but didn't want to use it in favor of a more
        //"robust" set of methods to demo patterns
        switch (this.operator) {
            case '+':
                newVal = this.add(this.lastNumber, displayedNumber);
                break;
            case '-':
                newVal = this.subtract(this.lastNumber, displayedNumber);
                break;
            case '*':
                newVal = this.multiply(this.lastNumber, displayedNumber);
                break;
            case '/':
                newVal = this.divide(this.lastNumber, displayedNumber);
                break;
        }
        this.setVal(newVal);
        this.lastNumber = newVal;
    }
};


To use the Calculator object, create a new instance and pass the names of the HTML container objects into the constructor (the container objects identify the IDs of controls used to display calculations – see the HTML code below):

var calc = null;
window.onload = function () {
    calc = new Calculator('currNumber', 'eq');
};


The HTML used to render the calculator can reference the calc object created when the page loads. The following code demonstrates how this can be done to handle events as different div elements are clicked. I normally prefer to wire-up events to event handlers using jQuery in “real-world” applications to keep the HTML clean but wanted to focus on JavaScript patterns and avoid introducing additional libraries for this post. I’m not a big fan of defining onclick and other event handlers directly on HTML elements but let it slide for this post.

<div class="Calculator">
    <div class="CalculatorHead">
        <div id="eq" class="Equation"></div>
        <div id="currNumber" class="CurrentNumber">0</div>
    </div>
    <div>
        <div class="Button" onclick="calc.numberClick(event);">7</div>
        <div class="Button" onclick="calc.numberClick(event);">8</div>
        <div class="Button" onclick="calc.numberClick(event);">9</div>
        <div class="Button" onclick="calc.setOperator('/');">/</div>
        <div class="Button rowspan2" onclick="calc.clearNumbers();">C</div>
    </div>
    <div>
        <div class="Button" onclick="calc.numberClick(event);">4</div>
        <div class="Button" onclick="calc.numberClick(event);">5</div>
        <div class="Button" onclick="calc.numberClick(event);">6</div>
        <div class="Button" onclick="calc.setOperator('*');">*</div>
    </div>
    <div>
        <div class="Button" onclick="calc.numberClick(event);">1</div>
        <div class="Button" onclick="calc.numberClick(event);">2</div>
        <div class="Button" onclick="calc.numberClick(event);">3</div>
        <div class="Button" onclick="calc.setOperator('-')">-</div>
        <div class="Button rowspan2" onclick="calc.setOperator('=');">=</div>
    </div>
    <div>
        <div class="Button colspan2" onclick="calc.numberClick(event);">0</div>
        <div class="Button" onclick="calc.numberClick();">.</div>
        <div class="Button" onclick="calc.setOperator('+');">+</div>
    </div>
</div>

 

The Prototype Pattern provides a nice way to structure JavaScript code but there are several other roads you can travel if desired. In this next post I’ll talk about the Revealing Module Pattern and explain how it can be used.

Demos of all the patterns covered in this series can be downloaded below.

Download Code

Creating a Line Chart using the HTML 5 Canvas

The HTML 5 canvas is capable of rendering lines, shapes, images, text and more without relying on a plugin. Although the canvas element isn’t supported by older browsers, the latest version of all major browsers (IE, Safari, Chrome, Firefox and Opera) now support the canvas making it an option for rendering charts, graphs and other types of visual data. In cases where a browser doesn’t support the canvas, a fallback can be provided that renders data using Silverlight, Flash or another type of plugin.

In a previous post I walked through the fundamentals of using the HTML 5 canvas to render different types of shapes. In this post I’ll discuss how the canvas can be used to render a line chart using JavaScript. An example of the chart that will be discussed is shown next:

 

To render the chart a JavaScript object named CanvasChart was created that handles rendering all of the lines, shapes and text shown above. An example of defining CanvasChart settings and calling its render() function is show next. The render() function accepts the canvas element ID as well as a JSON object that defines chart properties and data to be used in the rendering process.

<!DOCTYPE html>
<html>
<head>
    <title>Canvas Chart Demo</title>
    <script src="Scripts/jquery-1.6.min.js" type="text/javascript"></script>
    <script src="Scripts/canvasChart.js" type="text/javascript"></script>
    <script type="text/javascript">

        $(document).ready(function () {
            var dataDef = { title: "US Population Chart",
                            xLabel: 'Year',
                            yLabel: 'Population (millions)',
                            labelFont: '19pt Arial',
                            dataPointFont: '10pt Arial',
                            renderTypes: [CanvasChart.renderType.lines, CanvasChart.renderType.points],
                            dataPoints: [{ x: '1790', y: 3.9 },
                                         { x: '1810', y: 7.2 },
                                         { x: '1830', y: 12.8 },
                                         { x: '1850', y: 23.1 },
                                         { x: '1870', y: 36.5 },
                                         { x: '1890', y: 62.9 },
                                         { x: '1910', y: 92.2 },
                                         { x: '1930', y: 123.2 },
                                         { x: '1950', y: 151.3 },
                                         { x: '1970', y: 203.2 },
                                         { x: '1990', y: 248.7 },
                                         { x: '2010', y: 308.7}]
                           };
            CanvasChart.render('canvas', dataDef);
        });

    </script>
</head>
<body style="margin-left:50px;margin-top:50px;">
    <canvas id="canvas" width="800" height="600"></canvas>
</body>
</html>


While the CanvasChart object is only a prototype at this point, it demonstrates several key features of the canvas element that can be used in applications including rendering lines, shapes, gradients, text and even transformed text. Let’s take a look at how the CanvasChart object was created.

Rendering Gradients and Text

The code for the CanvasChart object is located in a file named canvasChart.js. The code starts by defining a CanvasChart object that exposes two members named renderType and render. renderType is used to define what will be rendered on the chart (currently it supports rendering lines and points) while render() is used to render the data on the canvas as well as the associated labels for the x and y axes. The skeleton code for CanvasObject is shown next:

var CanvasChart = function () {
    var ctx;
    var margin = { top: 40, left: 75, right: 0, bottom: 75 };
    var chartHeight, chartWidth, yMax, xMax, data;
    var maxYValue = 0;
    var ratio = 0;
    var renderType = { lines: 'lines', points: 'points' };

    return {
        renderType: renderType,
        render: render
    };
} ();

 

The render() function accepts the canvas ID within the page as well as a JSON object that defines details about labels, font sizes, data points and more:

var render = function(canvasId, dataObj) {
    data = dataObj;
    getMaxDataYValue();
    var canvas = document.getElementById(canvasId);
    chartHeight = canvas.attr('height');
    chartWidth = canvas.attr('width');
    xMax = chartWidth - (margin.left + margin.right);
    yMax = chartHeight - (margin.top + margin.bottom);
    ratio = yMax / maxYValue;
    ctx = canvas.getContext("2d");
    renderChart();
}

 

The function starts by assigning the dataObj parameter to a variable within the CanvasChart object and then calls an internal function named getMaxDataYValue(). The getMaxDataYValue() function determines the maximum Y value for the data points. From there, the render() function locates the target canvas element within the page, calculates width and height values, and accesses the canvas’s 2D context that will be used to draw. Finally, a call is made to renderChart() to start the rendering process.

The renderChart() function orchestrates different drawing functions and handles rendering the background, lines, labels and data by calling the respective functions:

var renderChart = function () {
    renderBackground();
    renderText();
    renderLinesAndLabels();

    //render data based upon type of renderType(s) that client supplies
    if (data.renderTypes == undefined || data.renderTypes == null) data.renderTypes = [renderType.lines];
    for (var i = 0; i < data.renderTypes.length; i++) {
        renderData(data.renderTypes[i]);
    }
}

 

Different canvas features are used such as gradients and transforms in the CanvasChart object. For example, the renderBackground() function shows how linear gradients can be created:

var renderBackground = function () {
    var lingrad = ctx.createLinearGradient(margin.left, margin.top, xMax - margin.right, yMax);
    lingrad.addColorStop(0.0, '#D4D4D4');
    lingrad.addColorStop(0.2, '#fff');
    lingrad.addColorStop(0.8, '#fff');
    lingrad.addColorStop(1, '#D4D4D4');
    ctx.fillStyle = lingrad;
    ctx.fillRect(margin.left, margin.top, xMax - margin.left, yMax - margin.top);
    ctx.fillStyle = 'black';
}

 

The renderBackground() function uses the 2D context’s createLinearGradient() function to define a gradient that has 4 gradient stops. Once the gradient is defined it is assigned to the fillStyle property and then rendered to a rectangular area using the fillRect() function.

CanvasChart also demonstrates how text can be manipulated using transforms. The text displayed on the Y axis is rotated so that it displays vertically:

 

image

 

This is accomplished by using the canvas element’s rotate transform functionality which is found in the renderText() function:

var renderText = function renderText() {
    var labelFont = (data.labelFont != null) ? data.labelFont : '20pt Arial';
    ctx.font = labelFont;
    ctx.textAlign = "center";

    //Title
    var txtSize = ctx.measureText(data.title);
    ctx.fillText(data.title, (chartWidth / 2), (margin.top / 2));

    //X-axis text
    txtSize = ctx.measureText(data.xLabel);
    ctx.fillText(data.xLabel, margin.left + (xMax / 2) - (txtSize.width / 2), yMax + (margin.bottom / 1.2));

    //Y-axis text
    ctx.save();
    ctx.rotate(-Math.PI / 2);
    ctx.font = labelFont;
    ctx.fillText(data.yLabel, (yMax / 2) * -1, margin.left / 4);
    ctx.restore();
}

 

The key section of this code is the call to ctx.save() (toward the bottom of the function shown above) which saves the current state of the canvas so that it can be restored. This is necessary so that the entire canvas isn’t rotated. Once the current canvas state is saved, a call to the rotate() function is made to rotate the canvas. The text is then drawn for the vertical axis using the fillText() function. Once the rotated text is rendered the canvas is restored back to its saved state (the state before the rotate transform was applied and the text was rendered).

After the x and y axis text is rendered, the CanvasChart object makes a call to renderLinesAndLabels() to handle rendering the horizontal and vertical lines.

var renderLinesAndLabels = function renderLinesAndLabels() {
    //Vertical guide lines
    var yInc = yMax / data.dataPoints.length;
    var yPos = 0;
    var yLabelInc = (maxYValue * ratio) / data.dataPoints.length;
    var xInc = getXInc();
    var xPos = margin.left;
    for (var i = 0; i < data.dataPoints.length; i++) {
        yPos += (i == 0) ? margin.top : yInc;
        //Draw horizontal lines
        drawLine(margin.left, yPos, xMax, yPos, '#E8E8E8');

        //y axis labels
        ctx.font = (data.dataPointFont != null) ? data.dataPointFont : '10pt Calibri';
        var txt = Math.round(maxYValue - ((i == 0) ? 0 : yPos / ratio));
        var txtSize = ctx.measureText(txt);
        ctx.fillText(txt, margin.left - ((txtSize.width >= 14)?txtSize.width:10) - 7, yPos + 4);

        //x axis labels
        txt = data.dataPoints[i].x;
        txtSize = ctx.measureText(txt);
        ctx.fillText(txt, xPos, yMax + (margin.bottom / 3));
        xPos += xInc;
    }

    //Vertical line
    drawLine(margin.left, margin.top, margin.left, yMax, 'black');

    //Horizontal Line
    drawLine(margin.left, yMax, xMax, yMax, 'black');
}

 

Lines are normally drawn using the 2D context’s moveTo() and lineTo() functions which I wrapped in a function named drawLine() to simplify the process:

var drawLine = function drawLine(startX, startY, endX, endY, strokeStyle, lineWidth) {
    if (strokeStyle != null) ctx.strokeStyle = strokeStyle;
    if (lineWidth != null) ctx.lineWidth = lineWidth;
    ctx.beginPath();
    ctx.moveTo(startX, startY);
    ctx.lineTo(endX, endY);
    ctx.stroke();
    ctx.closePath();
}


At this point the canvas looks like the following:

image

Rendering Data

Once the labels and lines are rendered, CanvasChart handles rendering the data points by calling a function named renderData(). This function handles iterating through the JSON   data points and drawing lines, points or both depending upon the settings passed to CanvasChart’s render() function. Lines are drawn to connect the different data points through calls to the drawLine() function shown earlier while circles are drawn for specific data points by making calls to the 2D context’s arc() function. The circles that are rendered have a radial gradient applied to them using the createRadialGradient() function:

 

var renderData = function renderData(type) {
    var xInc = getXInc();
    var prevX, prevY = 0;

    for (var i = 0; i < data.dataPoints.length; i++) {
        var pt = data.dataPoints[i];
        var ptY = (maxYValue - pt.y) * ratio;
        if (ptY < margin.top) ptY = margin.top;
        var ptX = (i * xInc) + margin.left;

        if (i > 0 && type == renderType.lines) {
            //Draw connecting lines
            drawLine(ptX, ptY, prevX, prevY, 'black', 2);
        }

        if (type == renderType.points) {
            var radgrad = ctx.createRadialGradient(ptX, ptY, 8, ptX - 5, ptY - 5, 0);
            radgrad.addColorStop(0, 'Green');
            radgrad.addColorStop(0.9, 'White');
            ctx.beginPath();
            ctx.fillStyle = radgrad;
            //Render circle
            ctx.arc(ptX, ptY, 8, 0, 2 * Math.PI, false)
            ctx.fill();
            ctx.lineWidth = 1;
            ctx.strokeStyle = '#000';
            ctx.stroke();
            ctx.closePath();
        }

        prevX = ptX;
        prevY = ptY;
    }
}

 

Once the data points are rendered the chart looks like the following:

 

Conclusion

You can see that there’s a fair amount of JavaScript code required to use the canvas object. However, once the different API functions are understood it’s simply a process of calling the appropriate functions to render lines, text or shapes. Although the CanvasChart object shown here is only a prototype at this point, I hope it provides insight into what the HTML 5 canvas is capable of rendering and how some of the features it provides can be used.

Download Canvas Demo

WPF: Using ObjectDataProvider to Populate a ListBox

Introduction

There are lots of data binding options in WPF.  Which one you use will depend, among other things, on the source of your data.  if the source happens to be a collection of .NET objects then you may be interested in the ObjectDataProvider that is available in WPF.

Using the ObjectDataProvider allows you to reference the data source directly in the XAML markup.  (The more common alternative is to create a DataContext in the code behind).  One advantage offered by the ObjectDataProvider is that it can load the data asynchronously.  Although not important for the simple example here, it may be useful in a more complex, busier, real world application, especially one that has a lot of data to handle, and can produce a better user experience.

Another useful feature is that the ObjectDataProvider can pass parameters to a method or object instance of the class that’s being targeted.  I’ve not done that in this example, in order to keep things simple, but I’ll include it in the next blog on this topic.

 

A Data Source

Here’s a class that defines DrinkProduct objects:

    1 Imports System.Collections.ObjectModel

    2 Public Class DrinkProduct

    3 

    4     Enum MaterialType

    5         Granules

    6         Leaf

    7         Liquid

    8         Paste

    9         Powder

   10         Other

   11     End Enum

   12     Sub New(ByVal ID As String, ByVal Name As String, ByVal PackType As String, _

   13            ByVal BaseMaterial As MaterialType, ByVal Sales As Integer, ByVal Qty As Integer)

   14         Me.ProductID = ID

   15         Me.ProductName = Name

   16         Me.PackageType = PackType

   17         Me.Material = Material

   18         Me.AnnualSales = Sales

   19         Me.Quantity = Qty

   20     End Sub

   21 

   22     Private _ProductID As String

   23     Public Property ProductID() As String

   24         Get

   25             Return _ProductID

   26         End Get

   27         Set(ByVal value As String)

   28             _ProductID = value

   29         End Set

   30     End Property

   31 

   32     Private _ProductName As String

   33     Public Property ProductName() As String

   34         Get

   35             Return _ProductName

   36         End Get

   37         Set(ByVal value As String)

   38             _ProductName = value

   39         End Set

   40     End Property

   41 

   42     Private _PackageType As String

   43     Public Property PackageType() As String

   44         Get

   45             Return _PackageType

   46         End Get

   47         Set(ByVal value As String)

   48             _PackageType = value

   49         End Set

   50     End Property

   51 

   52     Private _Material As MaterialType

   53     Public Property Material() As MaterialType

   54         Get

   55             Return _Material

   56         End Get

   57         Set(ByVal value As MaterialType)

   58             _Material = value

   59         End Set

   60     End Property

   61 

   62     Private _quantity As Integer

   63     Public Property Quantity() As Integer

   64         Get

   65             Return _quantity

   66         End Get

   67         Set(ByVal value As Integer)

   68             _quantity = value

   69         End Set

   70     End Property

   71 

   72     Private _annualsales As Integer

   73     Public Property AnnualSales() As Integer

   74         Get

   75             Return _annualsales

   76         End Get

   77         Set(ByVal value As Integer)

   78             _annualsales = value

   79         End Set

   80     End Property

   81 

   82     Public Overrides Function ToString() As String

   83         Return Me.ProductName

   84     End Function

   85 

   86     Public Shared Function StockCheck() As ObservableCollection(Of DrinkProduct)

   87         Dim CurrentProducts As New ObservableCollection(Of DrinkProduct)

   88         With CurrentProducts

   89             .Add(New DrinkProduct("CF1kg", "Coffee Powder", "1 Kg", MaterialType.Powder, 15684, 1276))

   90             .Add(New DrinkProduct("CFB500", "Ground Coffee", "500 g", MaterialType.Powder, 22785, 12856))

   91             .Add(New DrinkProduct("CFG500", "Coffee Granules", "500 g", MaterialType.Granules, 19233, 5907))

   92             .Add(New DrinkProduct("MlkSkim4lt", "Skimmed Milk 4L", "4 Litre", MaterialType.Liquid, 13472, 2640))

   93             .Add(New DrinkProduct("Te500", "Tea", "500 g", MaterialType.Leaf, 8544, 235))

   94             .Add(New DrinkProduct("TeInst500", "Instant Tea", "500 g", MaterialType.Powder, 1009, 22))

   95             .Add(New DrinkProduct("MlkSkim1lt", "Skimmed Milk 1L", "1 Litre", MaterialType.Liquid, 28012, 2650))

   96             .Add(New DrinkProduct("HiJ300", "HiJuice Drink Mix", "300 g", MaterialType.Other, 17523, 179))

   97             .Add(New DrinkProduct("Sm400", "Smoothie", "400ml", MaterialType.Paste, 9346, 3284))

   98             .Add(New DrinkProduct("Beef300", "Beef Drink", "300 g", MaterialType.Granules, 8316, 1965))

   99             .Add(New DrinkProduct("Beef750", "Beef Drink", "750 g", MaterialType.Granules, 7612, 359))

  100             .Add(New DrinkProduct("MlkFC1lt", "Full Cream Milk", "1 Litre", MaterialType.Liquid, 32686, 4128))

  101 

  102         End With

  103 

  104         Return CurrentProducts

  105     End Function

  106 

  107 End Class

  108 

As you can see, it has six Public properties plus an overridden ToString method and a method named StockCheck that simply generates some sample data and returns the data in an ObservableCollection. 

The WPF Window

To keep things simple, the Window will contain only a ListBox.  This ListBox will display the ProductName property.  We’ll improve this display once we’ve got the basics sorted.

Here’s the initial markup for the UI for the Window:

 

    1 <Window x:Class="MainWindow"

    2    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    3    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    4    Title="MainWindow" Height="350" Width="375">

    5     <Grid>

    6         <ListBox Margin="5,24,13,45" Name="lstDrinks" />

    7 

    8     </Grid>

    9 </Window>

   10 

There’s no data and no explicit items for the ListBox, so there’s nothing much to see yet.  Let’s get some data.

The ObjectDataProvider

The first thing you need to do is to add an XML namespace to the Window:

  xmlns:local="clr-namespace:ObjectDataProviderBlogDemo"

 

This will map the WPF Window to the local assembly and supply the alias of “local”.  We can then reference any of the project’s other code in the XAML pane of the Window.  In our example, of course, we’ll want to access that DrinkProduct class.

Next, we create the ObjectDataProvider.  Like other data providers, its job is to fetch the data from the source and make it available to the controls in the UI.  Because this project only has a single WPF Window, I’m placing the ObjectDataProvider in the Resources collection of the Window:

    <Window.Resources>

        <ObjectDataProvider x:Key="DrinksInfo"

        ObjectType="{x:Type local:DrinkProduct}"

        MethodName="StockCheck"></ObjectDataProvider>

    </Window.Resources>

 

 

Things to note here:

  1. The ObjectDataProvider has been assigned a Key. This allows us to refer to it elsewhere in the markup.
  2. The ObjectType property is set to the DrinkProduct class.  This is only possible because we created the mapping to the project Assembly, giving us access to all its code.
  3. The MethodName property has been set to StockCheck. If you review the DrinkProduct class code above, you’ll see that this is the method that generates the sample data.

 

 Wiring the ListBox to the data

All that’s left to do is to wire up the ListBox with that provider.  Or to be more specific, with the StockCheck method of the DrinkProduct class that’s available from the provider.

        <ListBox Margin="5,24,13,45" Name="lstDrinks"

           ItemsSource="{Binding Source={StaticResource DrinksInfo}}"  />

The ItemsSource, as its name says, is the property that dictates what populates the items that are displayed in the ListBox.  In the sample above, there’s a Binding and that binding points to the ObjectDataProvider.

So the sequence that gets the data and populates the ListBox is:

  1. The ObjectDataProvider calls the StockCheck method of the DrinkProduct class.
  2. The StockCheck method creates and then returns a collection of DrinkProduct objects.
  3. Because the ListBox is bound to the ObjectDataProvider, it receives whatever data is being passed out. In this case it’s whatever is returned by the ToString property.
  4. The ListBox displays that specific data as its items.

That’s pretty much all there is to it in its simplest usage.  The finished result in this example will look like this:

 

finished

I've uploaded a copy of the demo project which you can download from here.

Windows Forms Graphics: How to Merge and Print Images

This example shows how to take two images, merge them side by side, then print them.  I’ve chosen to put them side by side, but you can easily change the logic so that they’re placed one on top of the other.

To shows the steps, I’ve used three PictureBoxes. 

PictureMerge1

Two of them have images assigned. The third PictureBox will be used to display the merged image.

It’s important to realize that there’s no need to have any of the images on display for the code to work. But it does make it a lot easier to see the steps.

The Merge function

Here’s a function that combines the two images. Essentially it creates a canvas large enough to take the size of both incoming images and then pastes one to the left side and one to the right.  OK, so it’s not really a canvas, but I think the analogy helps visualise it.

 Public Function MergeImages(ByVal Pic1 As Image, ByVal pic2 As Image) As Image

 

    Dim MergedImage As Image ' This will be the finished merged image

    Dim Wide, High As Integer ' Size of merged image

 

    ' Calculate Width and Height needed for composite image

    ' First, the Width:

    Wide = Pic1.Width + pic2.Width

 

    ' Height: Ensure that the new image is high enough for both images

    ' that we plan to place inside it.

    High = If(Pic1.Height >= pic2.Height, Pic1.Height, pic2.Height)

 

    ' Create an empty Bitmap the correct size to hold both images side by side

    Dim bm As New Bitmap(Wide, High)

    ' Get the Graphics object for this bitmap

    Dim gr As Graphics = Graphics.FromImage(bm)

 

    ' Draw the first source image at left side of new image

    gr.DrawImage(Pic1, 0, 0)

 

    ' Draw second source image, offset to the right edge of first source image

    gr.DrawImage(pic2, Pic1.Width, 0)

 

    ' Assign the merged bitmap you have just created as the image

    ' you are going to return for printing

    MergedImage = bm

 

    ' Finished with the Graphics object – dispose of it

    gr.Dispose()

 

    ' You now have an Image named MergedImage which you can return.

    Return MergedImage

 

  End Function

I don’t think there’s much explanation beyond the comments needed.  Obviously, two image objects are passed in and one is returned at the end of the process.

The Merge Button
All this button does is call the MergeImages function and passes in the images from the first two PictureBoxes.

  Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    PictureBox3.Image = MergeImages(PictureBox1.Image, PictureBox2.Image)

 

  End Sub

At this stage, the form will look like this:

PictureMerge2

The PrintDocument control
I dragged a PrintDocument control onto the form and it sits itself in the component tray.  The PrintDocument has a PrintPage event which does what you’d expect.  All that’s needed here is to give it the details of exactly what you want to print and how you want it laid out.  This code does that job:

 

  Private Sub PrintDocument1_PrintPage(ByVal sender As System.Object, ByVal e As System.Drawing.Printing.PrintPageEventArgs) Handles PrintDocument1.PrintPage

    Dim Rect As New Rectangle(20, 20, PictureBox3.Width, PictureBox3.Height)

    e.Graphics.DrawImage(PictureBox3.Image, Rect)

 

  End Sub

The first line creates a Rectangle that’s large enough to hold the finished image that will be in PictureBox3 after the Merge button has been used. (You’ll see from the screenshot that there’s a lot of unwanted whitespace in PictureBox3, and this is dealt with by the Print button that I’ll come to next.)  The values of 20,20 in that first code line fix the start point on the printed page for the top left corner of the image print.  Obviously, this can be changed.

The second line uses the DrawImage method of the System.Drawing.Image class.  It takes the image from PictureBox3 and draws it within a rectangular area described by the variable named Rect.

The Print Button

Here’s the code in the click event of the Print button:

  Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

    ' Resize PictureBox3 to take its merged image exactly

    PictureBox3.Width = PictureBox3.Image.Width + 2

    PictureBox3.Height = PictureBox3.Image.Height + 2

 

    '  Print the image

    PrintDocument1.Print()

  End Sub

The Print button does a bit of housework first. It removes any unneeded area of the PictureBox.  It doesn’t particularly matter in this example because the background is white, but if there was a coloured background that would be part of the printout, it would probably look better without any large areas of image-less color. 

How to add text to an image (2) – extending the user’s options

Introduction

In an earlier blog on this subject, I created a form that had a PictureBox, a TextBox and a couple of Buttons:

TextOnImage2

 

 

The user enters text in the textbox, then clicks the Go button to add the text to the picture.  The Save Picture button does what you’d expect.

You can see the code for the above in the earlier blog.

To be really useful, though, it would be much better if the user had more control over the look of the text. For instance, the position of the text, font size and colour of the text, as well as the path and file name for the saved image.

So this blog will add those features.

Here’s what version 2 looks like:

TextOnImage3

2.  Text Position

As you can see from the screenshot, I’ve used two NumericUpDowns to set the location of the text.  These two controls are named LeftPosition and TopPosition respectively. When the user clicks the Go button, those two values are passed into a simple function that takes them and returns a Point.  A Point object simply represents a location.  Using a function for this task is really overkill, but I’ve split all the steps into individual functions for two reasons.  Firstly, it makes it easier for you to see what each step consists of – e.g. setting position, font color, etc.  Secondly, it allows you (or me) to add further features to these basic functions later .

The function that returns the position for the text is named GetPosition and looks like this:

    Private Function GetPosition() As Point

        Return New Point(LeftPosition.Value, TopPosition.Value)

 

 

            End Function

 

The click event of the Go button, as in the example in the earlier blog, takes the information and draws the text on the image:

    Private Sub btnGo_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnGo.Click

 

        Dim bmpTemp As Bitmap = New Bitmap(PictureBox1.Image)

        Dim gfx As Graphics = Graphics.FromImage(bmpTemp)

        '  Find user's choices and use them with DrawString

        gfx.DrawString(txtTextToAdd.Text, New Font("Calibri", 14, FontStyle.Bold), Brushes.Black, GetPosition)

        PictureBox1.Image = bmpTemp

        gfx.Dispose()

 

    End Sub

The only change to the original code is the use of GetPosition, as shown in the fourth line in the code listing.

3.  Text Color

In a similar way, I’ve used a separate function to take the user’s choice of color from the combo box and create a brush of that color.  This brush is then used in the DrawString method to apply the required color to the text.

Here’s the function:

    Private Function GetBrushColour() As Brush

        Dim RequiredBrush As Brush

        RequiredBrush = New SolidBrush(Color.FromName(cboColorChoice.SelectedItem.ToString))

        Return RequiredBrush

 

 

          End Function

 

The key to this function is the FromName method which allows you to pass in a string that represents the name of a color.  This string is then translated into a Color object that can then be assigned to a brush.  Because I’ve used a combo box to restrict the choice of names, I can be sure that only acceptable names will be passed in.

TextOnImage5

 

  If you change this so that the user types in a string, you’ll need to be sure to build in a test that such a color name actually exists.  In a later blog, I’ll tweak this part of the sample so that all known colors are listed for the user to select from.

The DrawString line of the button click code can now be changed to:

        gfx.DrawString(txtTextToAdd.Text, New Font("Calibri", 14, FontStyle.Bold), GetBrushColour, GetPosition)

 

4.  Font Size

For the font size I’ve created a function named GetFont.  As I plan to add other font attributes to this function later, I haven’t given it the more restrictive name of GetFontSize that you may have expected. 

The font size is selected from the NumericUpDown that I’ve named DesiredFontSize.  In the Properties Window, I’ve restricted the available sizes from a minimum of 4 to a maximum of 72.  The default value is set to 12.

Here’s the function:

    Private Function GetFont() As Font

        Dim FontBuilder As New Font("Calibri", DesiredFontSize.Value, FontStyle.Bold)

        Return FontBuilder

 

 

        End Function

 

As you can see, the font is created in the first line of the function and the DesiredFontSize that the user sets in the NumericUpDown is applied.  To keep things simple, I’ve hard coded the font family and font style attributes of the font.  I’ll show you how to change this in a later blog.

The final version of the DrawString code now looks like this:

        gfx.DrawString(txtTextToAdd.Text, GetFont, GetBrushColour, GetPosition)

 

5.  Multiple Text Elements

One by-product of this approach is that it’s now possible to add more than one text item to the image. 

TextOnImage4

6.  Saving the Image

In place of the original hard coded path and file name, this version uses a SaveFileDialog named SaveEditedFileDialog.  The user can then select a path and file name.

Here’s the amended code for the Save Picture button:

    Private Sub btnSave_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnSave.Click

        If SaveEditedFileDialog.ShowDialog = DialogResult.OK Then

            PictureBox1.Image.Save(SaveEditedFileDialog.FileName, ImageFormat.Jpeg)

            MessageBox.Show("File saved to " & SaveEditedFileDialog.FileName)

        Else

            MessageBox.Show("Unable to save file to " & SaveEditedFileDialog.FileName, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error)

        End If

    End Sub

As most of us like to have some reassurance that everything’s gone OK, the message box lets the user know what’s happened.

Summary

This application is more useful now, but as always there are more improvements that can be applied and I’ll move on to those in a later blog.

How to delete selected items from a CheckedListBox

 

A problem that often crops up is how to delete one or more items from a collection.  In the case of this example the collection is a collection of strings displayed as a list in a CheckedListBox.

 

CheckedListBox1

 

Deleting a single item at a time

This code will delete a selected item:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        CheckedListBox1.Items.Remove(CheckedListBox1.CheckedItems(0))

    End Sub

In this example, each time the button is clicked one checked item is deleted.  The key to this is the CheckedItems collection, which is a list that stores details of all the items that are currently checked.  The code above navigates to that collection, finds the first item that’s contained in it, and removes it. 

It will keep removing further individual items each time the button is clicked.  And because the collection of items is displayed top to bottom in the CheckedListBox, it will always remove the checked item that is highest on the list first

If you try this code, you’ll probably soon find a flaw in it. If you continue to click when there are no items checked, the application will crash.  The reason is that the collection of checked items will be empty, so when you try and do something with its first (non-existent) element, it gets red in the face, stamps its little foot and refuses to play any more.

The fix is easy.  Just insert a test that there is at least one element in the CheckedItems collection:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        If CheckedListBox1.CheckedItems.Count > 0 Then CheckedListBox1.Items.Remove(CheckedListBox1.CheckedItems(0))

    End Sub

 

Deleting multiple items

In the example shown in the screenshot, you’ll probably want to remove all the checked items in one go.  To do this requires a bit more work, but not a lot.  Here’s the code:

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        With CheckedListBox1

            If .CheckedItems.Count > 0 Then

                For checked As Integer = .CheckedItems.Count – 1 To 0 Step -1

                    .Items.Remove(.CheckedItems(checked))

                Next

            End If

        End With

    End Sub

For the reason I described above, the first thing that happens is a test that there is at least one item checked.

Next, the For/Next loop runs through the CheckedItems collection and removes each element one after the other.  The key to this code working properly is that the loop works backward from the end of the collection back to the start.  This is a common requirement when you’re manipulating collections and you’ll often find that if you work through a collection from start to finish and try and make changes, your app will crash. 

 

An annoying thing about clicking a CheckedListBox

Nothing to do with deleting items, but if you’ve found that it’s really annoying that you click on a checkbox and the item isn’t selected, so you have to click a second time, then let me introduce you to the CheckOnClick property.  Select the CheckedListBox in design view and then go to the Properties Window.  Scroll down to the CheckOnClick property which will be defaulted to False.  Change it to True.  Problem solved.

 

Sample Project

I’ve uploaded a sample project that you can access from here.

An introduction to dates and times in Visual Basic.NET (3)

Introduction
Earlier blogs, here and here, introduced the basics of the DateTime class. In this article, I’ll look at the TimeSpan object.  As I explained there, the DateTime object is a particular moment in time and sometimes that’s what you’ll need.  Other times though you will need to know how much time exists between two DateTimes.  The TimeSpan object is designed to calculate and hold that value for you.

A TimeSpan will hold details of a duration or a period of time – a total number of years, months, days, hours, minutes, seconds, milliseconds, etc. Although it’s a very useful object, it isn’t always the easiest to use.  Let’s see if I can cut a clear path thrugh the important stuff you need to know.

Creating a TimeSpan
You create a TimeSpan just like you create any other object in .NET.  You use one of the four constructors and you pass in details that set a length of time as its value. (Or don’t, in which case the value will be zero).

  Dim ts As New TimeSpan(10, 30, 0)

  Console.WriteLine(ts.Hours)

The above example creates a TimeSpan that has a value of 10 hours and 30 minutes.  Other overloads of the constructor allow you to pass in other combinations of time.

There is an even easier way:

    ts = TimeSpan.FromMinutes(15)

    Console.WriteLine(ts.TotalMinutes)

This approach uses the FromXXX method of the TimeSpan and there are versions that use everything from days to milliseconds.

In most cases, you probably won’t want to hard code the value of a TimeSpan value in this way.  Probably the most useful feature of a TimeSpan is its ability to take dates and times from user input or data sources and calculate the difference between them, or manipulate them by adding or subtracting chunks of time.

Calculating a TimeSpan from user input
A common scenario is where you take a date as user input and you calculate how much time difference there is between that date and today. As a first example, I’ll use a textbox for the input.  But if you have any experience of users, you’ll know that this will mean that you’ll have to build in a lot of checking to avoid crashes when they input invalid data.  Here’s the code sample:

    Dim ts As TimeSpan

    ts = (DateTime.Now.Subtract(CDate(txtDateFromUser.Text)))

    Console.WriteLine(ts.TotalDays.ToString)

The sample assumes that the user enters a date into a textbox named txtDateFromUser.  The second line uses the Subtract method of the DateTime class. It takes today’s date and subtracts whatever date the user has entered into the textbox. At that point, the TimeSpan holds all the details of the time difference between the two dates.  As you saw in the first blog on this topic, internally VB uses Ticks as its counting mechanism and that’s not a value that’s always useful to us.

So the third line takes the current value that’s held in the TimeSpan and calculates the total number of days that it represents. It then writes this value to the console.

It’s possible to find the total days, minutes, second and milliseconds in the same way.  Note that the values are calculated as Longs, so you’ll also get a decimal point and a range of decimal values.  You can hide these by using CInt or by employing one of the Math functions.

    Dim ts As TimeSpan

 

    If IsDate(txtDateFromUser.Text) Then

      ts = (DateTime.Now.Subtract(CDate(txtDateFromUser.Text)))

      Console.WriteLine(CInt(ts.TotalHours.ToString))

    End If

The example above removes the decimal places and also checks that the user has input a valid date.

In the real world context you’d probably use something like a DateTimePicker to constrain the user’s choices. Taking the scenario I’ve used above, where we are calculating the difference between a user’s choice and today, the following code will do the trick:

  Private Sub DateTimePicker1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DateTimePicker1.ValueChanged

    Dim ts As TimeSpan

    ts = DateTime.Now.Subtract(DateTimePicker1.Value)

    Console.WriteLine(ts.TotalDays)

  End Sub

Hours vs TotalHours
You’ve seen that I’ve used the Hours property and the TotalHours property in various examples. If you’re wondering about the difference between them, then here’s the scoop.  If you have a TimeSpan whose value is, say, 1 Day, 5 Hours, then it’s Hours value will be 5.  The Hours property isn’t interested in any other part of the value.  The TotalHours property, on the other hand, does a bit of simple math it takes that 1 Day, 5 Hours total and calculates how many hours in total that represents.  So the TotalHours property would return 29.  There are other TotalXXX properties available in the TimeSpan class.

Display multiple time elements
All the examples so far have only displayed one kind of time element.  That is, I’ve written either the value of hours, or days, or minutes.  Sometimes you’ll want to display a combination, or a breakdown.  This code uses the DateTimePicker, gets the user’s choice and then displays the days, hours, minutes and seconds that have elapsed between the chosen date and now:

    Dim ts As TimeSpan

    ts = DateTime.Now.Subtract(DateTimePicker1.Value)

    '  Build the format string

    Console.WriteLine(String.Format("{0} days, {1} hours, {2} minutes, {3} seconds",

                               ts.Days, ts.Hours, ts.Minutes, ts.Seconds))

The result will look something like this:

16 days, 0 hours, 0 minutes, 42 seconds

Of course, I used the word ‘elapsed’ just now, but it’s possible that the user might select a date in the future.  In that case, the above code will work fine, but the value will be a minus figure.

You can explicitly check for this and post up a message:

    Dim ts As TimeSpan

    ts = DateTime.Now.Subtract(DateTimePicker1.Value)

    If ts.TotalSeconds > 0 Then

      Console.WriteLine("You selected a date in the past")

    End If

Or, to cover all the bases:

    Dim ts As TimeSpan

    ts = DateTime.Now.Subtract(DateTimePicker1.Value)

    Console.WriteLine("You selected a date " & If(ts.TotalSeconds > 0, "in the past.", "in the future."))

If you try the above code and choose today’s date in the DateTimePicker you’ll find that the message returns “in the future”.  This is another version of that kind of Now vs Today scenario.  The DateTimePicker has its time value defaulted to midnight, so  -  assuming you don’t run the app at exactly midnight – there will always be some time gap between the two values.

WPF TextBox: Spell Checking

One of the potentially very useful features of the WPF TextBox is that it has a spell checking function built-in.  I say ‘built in’, but actually it’s not very obvious how to access it.  if you select a TextBox and view the Properties pane, you wont find it listed in there, nor will you bring it into view if you use the search window of the Properties pane.  As far as I know, the only way to include spell checking is to manually code it, either in XAML or in code-behind. 

Here’s the markup for a TextBox:

    <TextBox x:Name="DemoTextBox" Margin="3,5,25,0" TextWrapping="wrap" >

      The Spell Checker helps if you can't spel very well.

    </TextBox>

If you want to enable the spell checker in code, you can use code-behind like this:

  Private Sub Window2_Loaded(ByVal sender As Object, ByVal e As System.Windows.RoutedEventArgs) Handles Me.Loaded

    DemoTextBox.SpellCheck.IsEnabled = True

  End Sub

Alternatively, you could edit the original markup to include the SpellCheck property.

    <TextBox x:Name="DemoTextBox" Margin="3,5,25,0" TextWrapping="wrap"

            SpellCheck.IsEnabled="True">

      The Spell Checker helps if you can't spel very well.

    </TextBox>

One small advantage of using the XAML option is that you can see any typos you’ve made at design time:

TextBox7

Obviously, if you use the code-behind version, the spell checker won’t kick in until the window is actually loaded at run time.  However, as the TextBox control is really designed to take user input, not yours, this is a very moot point.

When you run the application and make a spelling error, the incorrectly spelled word is underlined in red.  Right-clicking the offending word brings up a list of suggested replacements:

TextBox8

The default list of words is based on the dictionary used by MS Office.  Depending on the language you have set for your OS, you may find the list of replacements will be in one of four languages – English, French, German, or Spanish.  

In .NET 4, it’s now possible to add your own list of acceptable words.  The steps for this are as follows:

In a plain text file, create a list of words that you want to allow.  You can use Notepad for this:

Textbox9

Save this text file and name it.  You can use any file extension you like.

In the markup for the TextBox, ensure that SpellCheck.IsEnabled is set to True.

Add an XML namespace reference to the class (usually this will be your window class). Point this namespace alias to the .NET System namespace.

 

<Window x:Class="Window2"

   xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

   xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  xmlns:sys="clr-namespace:System;assembly=system"

Add the CustomDictionaries property to the TextBox markup.  Use the namespace alias to access the System.Uri class and assign the path and file name of the dictionary to it as shown below.

       <TextBox x:Name="DemoTextBox" Margin="3,5,25,0" TextWrapping="wrap"

            SpellCheck.IsEnabled="True" >

      <SpellCheck.CustomDictionaries>

        <sys:Uri>F:GedsDictionary.dic</sys:Uri>

      </SpellCheck.CustomDictionaries>

    </TextBox>

Run the application.  Now, when any of the words that you have added to the list are used in the TextBox, they will be accepted and not marked as misspelled.  Note, though that your additional entries are case sensitive, so if you think someone’s going to use initial capital letter or not, then you need to include both versions in the list.

textbox10

As a side note, You might have noticed that the SpellCheck class also has a property named SpellingReform.  If you’ve wondered what it’s for, then all I can tell you is that Vous devez parler français oder Sie müssen Deutsch sprechen for this property to be any use to you.  It only applies to French and German.

WPF: Calculating arithmetic values on the fly when data binding

Introduction

I’m not sure that’s the clearest title I’ve ever written, but the scenario I have in mind is this:  You have various UI elements of a WPF Window bound to data, most of them with a path to a specific field.  But you want one TextBlock to display the result of a calculation that’s applied to a field.

To be specific, in this example the data includes an Annual Sales figure.  You want to divide this by 12 in order to display the average monthly sales. You can’t include this kind of calculation in the XAML, so how is it done?

The answer is to use that useful little class, the value converter.  This intercepts the annual total as it’s being passed to the TextBlock and does the required arithmetic.  Then it passes on the revised value and this is shown in the Window.

The Grid

In my last blog item, I used StackPanels to layout the various UI elements.  In this project, I’ve used a Grid.  I’ve found that once you get past the stage where you need to use more then two nested panels, it’s often easier to use a Grid instead.

The Grid has three columns and four rows and at design time looks like this:

SalesConverter1 

The markup that creates the above layout is :

    <Grid DataContext="{Binding Source={StaticResource DrinksInfo}}" >

 

        <Grid.RowDefinitions>

            <RowDefinition Height="1*" />

            <RowDefinition Height="1*" />

            <RowDefinition Height="1*" />

            <RowDefinition Height="1*" />

        </Grid.RowDefinitions>

        <Grid.ColumnDefinitions>

            <ColumnDefinition Width="2*" />

            <ColumnDefinition Width="1*" />

            <ColumnDefinition Width="1*" />

        </Grid.ColumnDefinitions>

 

         <ListBox            

           Name="lstDrinks" ItemsSource="{Binding}" 

            IsSynchronizedWithCurrentItem="True" Grid.RowSpan="4"

            HorizontalAlignment="Left" Margin="22,12,0,0" 

            VerticalAlignment="Top" Width="120" />

 

        <TextBlock Margin="2,12,0,0"   Grid.Column="1" Text="Product ID" />

        <TextBlock Grid.Column="2"  Margin="2,12,0,0"  Text="{Binding Path=ProductID}" />

        <TextBlock Margin="2,12,0,0"   Grid.Column="1" Grid.Row="1" Text="Stock Quantity" />

        <TextBlock Grid.Column="2"  Margin="2,12,0,0" Grid.Row="1" Text="{Binding Path=Quantity}" />

        <TextBlock Margin="2,12,0,0"   Grid.Column="1" Grid.Row="2" Text="Package" />

        <TextBlock Grid.Column="2"  Margin="2,12,0,0"    Grid.Row="2" Text="{Binding Path=PackageType}" />

        <TextBlock Margin="2,12,0,0"   Grid.Column="1" Grid.Row="3" Text="Monthly Sales" />

        <TextBlock Margin="2,12,0,0"   Grid.Column="2" Grid.Row="3"

                   Text="{Binding Path=AnnualSales, Converter={StaticResource MonthlyStats}}" />

 

    </Grid>

Starting from the top, the DataContext of the Grid is set to a StaticResource named DrinksInfo.   DrinksInfo is an ObjectDataProvider refers to a method that creates some sample data for this application. The XAML is shown below.  If you’re not familiar with how ObjectDataProvider works or how to map to another class, you might want to check my last two blog items as I’ve covered it there.

The row and column definitions for the Grid ensure that the real estate is divided out between the rows and columns.

The ListBox gets its items from its nearest binding.  In this case, that will be the DataContext of its parent element, the Grid.

The eight TextBlocks contain either a label or the value of a bound field.  Again, I’ve covered similar territory in my previous blogs, so I won’t go through the first seven again.  The final TextBlock is the one that has an arithmetic calculation performed in order to get its content.

Before I move on to how that’s done, here is the markup for the ObjectDataProvider:

 

        <ObjectDataProvider x:Key="DrinksInfo"

        ObjectType="{x:Type local:DrinkProduct}"

        MethodName="StockCheck">

        </ObjectDataProvider>

 

The ValueConverter

Here’s the code for the SalesConverter class:

 

    1 Public Class SalesConverter

    2     Implements IValueConverter

    3 

    4     Public Function Convert(ByVal value As Object, ByVal targetType As System.Type,

    5                             ByVal parameter As Object,

    6                             ByVal culture As System.Globalization.CultureInfo) As Object _

    7                             Implements System.Windows.Data.IValueConverter.Convert

    8 

    9         Dim Result As Integer = Integer.Parse(value.ToString)

   10         Result /= 12

   11         Return Result.ToString

   12 

   13     End Function

   14 

   15     Public Function ConvertBack(ByVal value As Object, ByVal targetType As System.Type,

   16                                 ByVal parameter As Object,

   17                                 ByVal culture As System.Globalization.CultureInfo) As Object _

   18                                 Implements System.Windows.Data.IValueConverter.ConvertBack

   19 

   20         Throw New NotImplementedException()

   21     End Function

   22 End Class

The Convert method takes whatever is bound to the Text property of that final TextBlock in the Window.  Because it’s passed in as an Object, it has to be parsed into an Integer.  Of course, this only works because |i know for sure that the field being handled is going to be an integer.  In a production application, I’d be sure to validate this.

This integer value is then divided by 12 to find the monthly sales value and that’s returned to the caller.  In this case, the caller is the binding to the Text property of the TextBlock.

The next key step is to create an instance of this value converter in the XAML for the Window.  In the sample project, I’ve placed this in the Window.Resources collection:

       <local:SalesConverter x:Key="MonthlyStats" />

Notice the Key.  This is directly referenced in the markup for the final TextBlock in its Text property setting:

   Converter={StaticResource MonthlyStats}}" />

So, to summarize, the process is:

  1. As the TextBlock is being updated, the binding fetches the Annual Sales figure for the current selection.
  2. But before it displays that figure, it finds the Converter and so it calls the Convert method, passing in the value of the current field.
  3. The converter takes that value, divides it by 12, then returns it.
  4. This calculated value is displayed in the TextBlock.

The finished result (which is pretty much the same as the design view you’ve already seen) is:

SalesConverter2

I've attached the demo project that you can download and try out.

 

Click event handler for a WPF Button

In a recent blog, I looked at how easy it is to add additional content to a WPF Button. Here’s the button I created for the demo:

GeorgeBestButton9

And this was created using the following markup:

 

    <Button  HorizontalAlignment="Left" Margin="28,27,0,0" Name="Button2" VerticalAlignment="Top" >

      <Button.Resources>

        <LinearGradientBrush x:Key="RedandWhite" EndPoint="0.329,0.872" StartPoint="0.671,0.128">

          <GradientStop Color="White" Offset="0.511"/>

          <GradientStop Color="Red" Offset="1"/>

          <GradientStop Color="Red" Offset="0.019"/>

        </LinearGradientBrush>

      </Button.Resources>

      <Button.Content>

        <StackPanel Background="{StaticResource RedandWhite}"> 

        <TextBlock Margin="5,5,5,8" TextWrapping="Wrap">Click here for more information </TextBlock>

          <Image Source="/WPFButtons;component/george-best.jpg" Width="66" Margin="0,2,0,5" />

          <TextBlock Margin="5,5,5,8" TextWrapping="Wrap">on George Best</TextBlock>

        </StackPanel>

      </Button.Content>

    </Button>

 

  Someone contacted me with a question about accessing the click event of a button like this one – that is, one where the surface of the button in design view is pretty crowded with other elements.  People who have been working with WinForms for a long time probably are in the habit of double-clicking on the button as a quick way of getting the event handler stub created for them.  This still generally works in WPF.  But, as the questioner found out, if you double click on, say, the image or one of the text blocks in this example button, you’ll usually get an event handler that’s related to the specific element you double-clicked.    So in the case of an image, that’s the ImagedFailed event handler. As I’m sure you’ll know, you get the default event for the particular element. In the case of a TextBlock or StackPanel, however, you just get stony silence – it just sits there showing the XAML pane and designer, steadfastly refusing to play the game with you.

  So with WPF, it’s probably better to move away from the double-click-to-display-the-stub approach and use one of two other ways.  Which one you choose depends on the needs of your application and your personal preference. 

The first way is the same as one that’s available in WinForms.  Manually select the tab for the code-behind, then select the element (control) in the first combo box, and then select the click event from the second combo box.   You’ll then have an event handler that includes a Handles clause.

The second, more WPF-ish, way is to add a pointer to the Click handler in the XAML pane.  You can do this by typing the word Click (in the case of a button), followed by the equals symbol.  You’ll then see a context menu that will let you create a new event handler, or – if there are any other button click events already coded – choose an existing one.

 

ButtonClickEvent

In the example above, you can see that there is already an event handler named Button2_click that I could use if I wanted to.  Alternatively, i can create a new event handler by clicking on the first choice shown there.

Event handlers that are created in this way don’t have a Handles clause attached to them.  And this of course can help the reusability of your event handlers.  Interestingly, as in the above example, the list of usable event handlers will also include any that already have a Handles clause that point to another button or buttons.   If you choose such an event in the XAML pane, your choice will be honoured, but the code behind isn’t changed to show this.  That is, the list of controls in the Handles clause isn’t changed to include the one you’ve just effectively added.  It’s not a problem, but if you’re used to reading through the Handles clauses to check which control is doing what in WinForms, you’ll need to break out of that habit when working with WPF.  You probably should anyway.  :-}

WP Like Button Plugin by Free WordPress Templates