Introduction to Windows 8 Metro & WinRT (part 1)


Welcome to the first in this two part series on developing Metro application in Windows 8. Part two is available here

Introduction to Windows 8 Metro & WinRT (part 2)

In this two part series, I will demonstrate just how easy it is to create your first Windows Metro application, and highlight some of the changes that you will need to be aware of if you are coming from a WPF, Silverlight or Windows Phone background. The series will concentrate specifically on the three different types of Metro application available to you in Visual Studio.

The first part will demonstrate how to create a blank Metro application, familiarise yourself with the location of the resources and files, and finally demonstrate how to load some data from your computer using the new async and await keywords in C# 5.0.

The second part will demonstrate how to create a Grid and Split Application, highlighting the differences between the two, and also show you the amazing “Simulator” that incidentally, will please project managers no end, as they will have to purchase far less hardware to test their Metro applications on.

    The first thing to do, is ensure you download the tools. In order to create a Windows Metro application, you will need to be running Windows 8 (consumer preview available here) and Visual Studio 11 (beta available here or any of the express editions. If you are using Windows 7 and Visual Studio 11 beta, or Visual Studio Express, then the metro templates will not be available to you in Visual Studio.

Windows 8

 

Windows8

Visual Studio 11

 

Visual Studio

 

Creating a Simple Metro Application

If you run Visual Studio, select New Project and then the Windows Metro Style template (Visual Basic template is at the bottom of this screenshot), also note that there are three application types available that are highlighted in yellow. Select the Blank Application Template and name the project BlankApplication and click OK

New Project

 

The first thing to notice is that your solution explorer has an Assets folder and a Common folder

 

Blank Solution

In the Common Folder you have a StandardStyles.xaml file that (as you might guess) contains the styles all Metro applications use, and since one of the Metro Guidelines is that “a Metro Style app should look like a Metro application”, these styles are invaluable. If you also look at both the XAML and code being of the App.xaml you will see that this works like WPF or Silverlight if you have ever used the navigation framework and it also explain why when you hit F5 you get a blank page

Viewing Images from my computer

If you double click on the BlankPage.xaml and add the following mark-up and code to click a button and load some images from your computer. Also be aware that everything in WinRT is asynchronous. Since it is Olympic year, I have a folder  in “My Pictures” on my computer with some aerial photos of the Olympic Village as a work in progress

XAML

<Page
x:Class="BlankApplication.BlankPage"
xmlns:local="using:BlankApplication"
mc:Ignorable="d">
<Grid Background="{StaticResource ApplicationPageBackgroundBrush}">
<Button Content="Find Pictures" HorizontalAlignment="Center" Command="{Binding Path=LoadImages}" Click="Button_Click" />
<Image x:Name="image1" />
</Grid>
</Page>

Code Behind

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI.Popups;
using Windows.Storage;
using Windows.Storage.Pickers;
using Windows.Storage.Streams;
// The Blank Page item template is documented at http://go.microsoft.com/fwlink/?LinkId=234238
namespace BlankApplication
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class BlankPage : Page
{
public BlankPage()
{
this.InitializeComponent();
}
/// <summary>
/// Invoked when this page is about to be displayed in a Frame.
/// </summary>
/// <param name="e">Event data that describes how this page was reached.  The Parameter
/// property is typically used to configure the page.</param>
protected override void OnNavigatedTo(NavigationEventArgs e)
{
}
private async void Button_Click(object sender, RoutedEventArgs e)
{
var dialog = new MessageDialog("Would you like to find some pictures?");
dialog.Commands.Add(new UICommand("Yes", null, "Yes"));
dialog.Commands.Add(new UICommand("No", null, "No"));
var result = await dialog.ShowAsync();
if (result.Id.ToString() == "Yes")
{
var picker = new FileOpenPicker();
picker.ViewMode = PickerViewMode.Thumbnail;
picker.SuggestedStartLocation = PickerLocationId.PicturesLibrary;
picker.FileTypeFilter.Add(".jpg");
var file = await picker.PickSingleFileAsync();
if (file != null)
{
IRandomAccessStream fileStream = await file.OpenAsync(FileAccessMode.Read);
var bitmapImage = new Windows.UI.Xaml.Media.Imaging.BitmapImage();
bitmapImage.DecodePixelHeight = 400;
bitmapImage.DecodePixelWidth = 400;
bitmapImage.SetSource(fileStream);
image1.Source = bitmapImage;
}
}
}
}
}

Run Application

If you select F5 in Visual Studio, and click on Find Pictures

Run

Find Pictures

Here you can see the text that you added to the command in the code behind

Find

View Images

Finally here you can view all the images that I have in the My Pictures folder on my computer

My Pics

As you can see there are a lot of similarities for WPF and Silverlight developers coming to WinRT, and though some libraries will differ it will not be that difficult to incorporate these differences to your existing toolset.

Get directory of an executing assembly in C# and Visual Basic


Continuing my series of short but useful tips and tricks, one usually needs to find the directory of an executing assembly. The simple console application below shows how to do this. The Visual Basic example is after the C# one.

C#

using System;
using System.IO;
using System.Reflection;
 
namespace ConsoleApplication2
{
internal class Program
{
private static void Main(string[] args)
{
Console.WriteLine("Directory: " + AssemblyDirectory());
Console.WriteLine("Location: " + Assembly.GetExecutingAssembly().Location);
Console.ReadKey();
}
 
public static string AssemblyDirectory()
{
var uri = new UriBuilder(Assembly.GetExecutingAssembly().CodeBase);
return Path.GetDirectoryName(Uri.UnescapeDataString(uri.Path));
}
 
}
}
 

Visual Basic

 

Imports System.Reflection
Imports System.IO
 
Module Module1
 
Sub Main()
Console.WriteLine("Directory: " + AssemblyDirectory())
Console.WriteLine("Location: " + Assembly.GetExecutingAssembly().Location)
Console.ReadKey()
End Sub
 
Public Function AssemblyDirectory() As String
Dim uri = New UriBuilder(Assembly.GetExecutingAssembly().CodeBase)
Return Path.GetDirectoryName(System.Uri.UnescapeDataString(uri.Path))
End Function
 
End Module

The calling thread must be STA, because many UI components require this


Whilst working on my current WPF application, I was at Sixes & Sevens trying to correct the following error;

Message: The calling thread must be STA, because many UI components require this

I ended up hacking my way out of this problem a week or so ago, hacks however, make me feel extremely dirty, and subscribing to the “leave code as you would like to find it” mantra meant one had to subsequently revisit it to “tidy-up”.  I have a strictly MVVM application that is complex and multithreaded, needing to update UI components from web service calls that typically are asynchronous. The issue here was that I was using code like this in my view model thinking I had access to the dispatcher.

Dispatcher.CurrentDispatcher.BeginInvoke((Action) (() =>
 

The mistake I made was in not getting a reference to the correct dispatcher.

To correct this issue, ensure you have a variable that gets a reference to the correct dispatcher when the view model is instantiated, you can then use this dispatcher in your view model, without having to pollute your code behind files.

private readonly Dispatcher dispatcher;
 
public DemoViewModel()
{
this.dispatcher = Dispatcher.CurrentDispatcher;
}

Single instance WPF application in C#


Update: 12/03/2012

I ran into some issues with the approach that I linked to below, and would not recommend it. It turns out that the best way to deal with this issue, is to use the Visual Basic instance detection classes (yes you can use these from C#). The sample code is available here

Note that is is more than likely that you will be retrofitting this to an existing project. If that is the case, make sure you double click the properties pane in visual studio and set your custom start-up file/class as shown below

startup

 

Original Post

Keeping in the same vein as my previous post, I frequently find that I have to solve the same problems at times. After a year or several months I usually move onto another project, consequently no longer have the source code, so I am posting this as a bit of a sticky as I am sure someone will find it useful.

Visual Basic has single instance classes one can use, one can import these into any C# application and consume them (that, after all,  is the real beauty of .NET), but I found that there was too much code, and too many classes, and it was taking me too long a little while back. I solve this problem using the Process class. Create a WPF application and use as follows;

using System.Diagnostics;
using System.Linq;
using System.Windows;
 
namespace SingleInstanceApp
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
IsAppAlreadyRunning();
}
 
private static void IsAppAlreadyRunning()
{
Process currentProcess = Process.GetCurrentProcess();
 
if (Process.GetProcessesByName(currentProcess.ProcessName).Any(p => p.Id != currentProcess.Id))
{
MessageBox.Show("Another instance is already running.", "Application already running",
MessageBoxButton.OK, MessageBoxImage.Exclamation);
Current.Shutdown();
return;
}
}
}
}

Copying an object in C# and Visual Basic


Sometimes there are classes you find you use in every project. I remember once (shudder) I, rather inelegantly instantiated a class, and performed a manual copy of all the properties in the object (when the pressure was on, and I just needed to make the thing work).

I have also found myself spending hours chasing subtle and hard to debug issues where ICloneable has been used -  which, incidentally, is widely accepted as an interface one ought never use – or Object.MemberwiseClone. It turns out the only way to do this correctly, is to serialise the object, and then use the deserialised object, implemented here using an extension method.

Even though this is quite straightforward, I still am posting this however , because I find I need to use this functionality frequently, and often I no longer have access to the source, or it takes ages to find the class. The Visual Basic code sample is after the C# one.

C#

using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
 
namespace ObjectCopierApp.Extensions
{
/// <summary>
/// Provides a method for performing deep copying of an object.
/// Binary Serialization is used to perform the copy.
/// </summary>
internal static class ObjectCopier
{
/// <summary>
/// Perform a deep copy of an object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
internal static T Clone<T>(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
 
// Don’t serialize a null object, simply return the default for that object
if (ReferenceEquals(source, null))
{
return default(T);
}
 
IFormatter formatter = new BinaryFormatter();
 
using (var stream = new MemoryStream())
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
}
}
 
 

Visual Basic

Imports System.IO
Imports System.Runtime.Serialization
Imports System.Runtime.Serialization.Formatters.Binary
 
Namespace ObjectCopierApp.Extensions
”’ <summary>
”’ Provides a method for performing deep copying of an object.
”’ Binary Serialization is used to perform the copy.
”’ </summary>
Friend NotInheritable Class ObjectCopier
Private Sub New()
End Sub
”’ <summary>
”’ Perform a deep copy of an object.
”’ </summary>
”’ <typeparam name="T">The type of object being copied.</typeparam>
”’ <param name="source">The object instance to copy.</param>
”’ <returns>The copied object.</returns>
<System.Runtime.CompilerServices.Extension()> _
Friend Shared Function Clone(Of T)(source As T) As T
If Not GetType(T).IsSerializable Then
Throw New ArgumentException("The type must be serializable.", "source")
End If
 
‘ Don’t serialize a null object, simply return the default for that object
If ReferenceEquals(source, Nothing) Then
Return Nothing
End If
 
Dim formatter As IFormatter = New BinaryFormatter()
 
Using stream = New MemoryStream()
formatter.Serialize(stream, source)
stream.Seek(0, SeekOrigin.Begin)
Return DirectCast(formatter.Deserialize(stream), T)
End Using
End Function
End Class
End Namespace

Cannot build Expression Blend Project using F5/Ctrl+Shift+B


Whenever I try build Expression Blend on a machine for the first time, I always encounter this error when I hit F5

The specified solution configuration "Debug|HPD" is invalid. Please specify a valid solution configuration using the Configuration and Platform properties (e.g. MSBuild.exe Solution.sln /p:Configuration=Debug /p:Platform="Any CPU") or leave those properties blank to use the default solution configuration.
Done building project "Name Of Your Project.sln" — FAILED.

Error

It goes without saying that it is irritating that you cannot use the application from the word go. I have encountered this error on both 32 and 64 bit windows versions, and resolve the issue thus;

Go into the advanced system settings (I am using windows 7)

01

Select the advanced tab, and click the “Environment Variables” button

02

Delete the “Platform” variable

03

After restarting Expression blend, you should find that you can F5/Ctrl+Shift+B to build your solution.

Encrypting files in C#.NET using the Advanced Encryption Standard (AES)


Cryptography

One of the biggest challenges when dealing with the security and encryption for a system, is the determination of the correct ciphering paradigm. In .NET, there is a copious amount of libraries available for use in the System.Cryptography namespace. A significant amount of these libraries have been deprecated, usually, due to vulnerabilities being subsequently exposed, so it is very easy to use something that may be as watertight as a sieve.

This is further compounded by the fact that the cryptography API’s are very detailed and low level – they are not easy to use for a novice – the consequences of setting a single parameter incorrectly results in a security implementation that may as well not exist. Consequently, it is imperative that this subject never be approached in a typical agile/sprint manner – security should definitely be approached using a waterfall model. Have no hesitation to advise any manager or architect that your solution “will be ready, when it is ready”. The agile methodology is typically about adding units of functionality in a YAGNI way, accruing technical debt that can be paid back later, and refactoring applied, this just simply not a correct or acceptable approach when dealing with the security of a system. Do ensure you take the time to do a lot of research, understanding the pitfalls of various implementations is vital to a robust security implementation.

The Advanced Encryption Standard (AES)

The abundance of so many different types of cryptography, implemented using Symmetric (same key is used to encrypt and decrypt) and Asymmetric (public key and private key used to encrypt and decrypt) algorithms has necessitated that Governments try and standardise implementations across departments, sites and even countries. The AES was released in 2001 as a replacement for the Data Encryption Standard (DES) which had been found to be susceptible to backdoors. This new standard has been widely adopted in commercial environments, as it had a requirement to be able to protect information for a minimum of 20 years or 30 years.

A number of papers were submitted in the application process for the AES by various academic institutions, with the winning cipher named Rijndael (pronounced rain-dahl) a play on the names of the authors of the paper, Joan Daemen and Vincent Rijmen (paper available here). I am sure you will agree that comprehension and implementation of the paper is better suited to domain experts. The algorithm was written by two gifted PhD calibre researchers, so your time as a developer is better suited to try and resolve the domain problems that your business is trying to solve (unless you are a cryptographer of course). You can be sure that researchers at Microsoft have done all the time consuming work of implementing and testing the algorithm, rather than to trying to implement the Rijndael Block Cipher yourself.

To this end, Microsoft have implemented the Rijndael Block Cipher in two in .NET  classes which, incidentally, both inherit from the SymmetricAlgorithm  abstract base class

  • RijndaelManaged.
  • AesManaged
    The AES algorithm essentially, is the Rijndael symmetric algorithm with a fixed block size and iteration count. This class functions the same way as the RijndaelManaged class but limits blocks to 128 bits and does not allow feedback modes. Most developers tend to favour using the RijndaelManaged class directly, as that is the one that is used in the FIPS-197 specification for AES but there are a couple of caveats. If you want to use RijndaelManaged  as AES and adhere to the specification ensure
  1. You set the block size to 128 bits 
  2. You do not use CFB mode, if you do, ensure the feedback size is also 128 bits 

Unlike some of the asymmetric implementations by Microsoft, the AES implementation allows you to work at a very high level of abstraction, reducing the amount of parameters you have to configure, hence the scope for error. I have created a class that allows you to encrypt and decrypt strings (your password), and then use this to encrypt a files from anywhere on your machine.

Thus far, the only way this algorithm can be broken is by using a technique known as brute force. This is done by a supercomputer(s) trying every known word in a language, and various password to try and generate the correct password. Typically, these types of programs run over weeks or even months, but can be increased  to millennia if the end user chooses a strong password to begin with, which is why having a well defined password policy is vital.

public MainWindow()
{
InitializeComponent();
 
byte[] encryptedPassword;
 
// Create a new instance of the RijndaelManaged
// class.  This generates a new key and initialization
// vector (IV).
using (var algorithm = new RijndaelManaged())
{
algorithm.KeySize = 256;
algorithm.BlockSize = 128;
 
// Encrypt the string to an array of bytes.
encryptedPassword = Cryptology.EncryptStringToBytes("Password", algorithm.Key, algorithm.IV);
}
 
string chars = encryptedPassword.Aggregate(string.Empty, (current, b) => current + b.ToString());
 
Cryptology.EncryptFile(@"C:\Users\Ira\Downloads\test.txt", @"C:\Users\Ira\Downloads\encrypted_test.txt", chars);
 
Cryptology.DecryptFile(@"C:\Users\Ira\Downloads\encrypted_test.txt", @"C:\Users\Ira\Downloads\unencyrpted_test.txt", chars);
}
 

I am using 256 bit (you can change this to 128 or 192)

using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
 
namespace AesApp.Rijndael
{
internal sealed class Cryptology
{
private const string Salt = "d5fg4df5sg4ds5fg45sdfg4";
private const int SizeOfBuffer = 1024*8;
 
internal static byte[] EncryptStringToBytes(string plainText, byte[] key, byte[] iv)
{
// Check arguments.
if (plainText == null || plainText.Length <= 0)
{
throw new ArgumentNullException("plainText");
}
if (key == null || key.Length <= 0)
{
throw new ArgumentNullException("key");
}
if (iv == null || iv.Length <= 0)
{
throw new ArgumentNullException("key");
}
 
byte[] encrypted;
// Create an RijndaelManaged object
// with the specified key and IV.
using (var rijAlg = new RijndaelManaged())
{
rijAlg.Key = key;
rijAlg.IV = iv;
 
// Create a decrytor to perform the stream transform.
ICryptoTransform encryptor = rijAlg.CreateEncryptor(rijAlg.Key, rijAlg.IV);
 
// Create the streams used for encryption.
using (var msEncrypt = new MemoryStream())
{
using (var csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
{
using (var swEncrypt = new StreamWriter(csEncrypt))
{
//Write all data to the stream.
swEncrypt.Write(plainText);
}
encrypted = msEncrypt.ToArray();
}
}
}
 
 
// Return the encrypted bytes from the memory stream.
return encrypted;
 
}
 
internal static string DecryptStringFromBytes(byte[] cipherText, byte[] key, byte[] iv)
{
// Check arguments.
if (cipherText == null || cipherText.Length <= 0)
throw new ArgumentNullException("cipherText");
if (key == null || key.Length <= 0)
throw new ArgumentNullException("key");
if (iv == null || iv.Length <= 0)
throw new ArgumentNullException("key");
 
// Declare the string used to hold
// the decrypted text.
string plaintext;
 
// Create an RijndaelManaged object
// with the specified key and IV.
using (var rijAlg = new RijndaelManaged())
{
rijAlg.Key = key;
rijAlg.IV = iv;
 
// Create a decrytor to perform the stream transform.
ICryptoTransform decryptor = rijAlg.CreateDecryptor(rijAlg.Key, rijAlg.IV);
 
// Create the streams used for decryption.
using (var msDecrypt = new MemoryStream(cipherText))
{
using (var csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
{
using (var srDecrypt = new StreamReader(csDecrypt))
{
// Read the decrypted bytes from the decrypting stream
// and place them in a string.
plaintext = srDecrypt.ReadToEnd();
}
}
}
 
}
return plaintext;
}
 
internal static void EncryptFile(string inputPath, string outputPath, string password)
{
var input = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
var output = new FileStream(outputPath, FileMode.OpenOrCreate, FileAccess.Write);
 
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
 
var algorithm = new RijndaelManaged {KeySize = 256, BlockSize = 128};
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(Salt));
 
algorithm.Key = key.GetBytes(algorithm.KeySize/8);
algorithm.IV = key.GetBytes(algorithm.BlockSize/8);
 
using (var encryptedStream = new CryptoStream(output, algorithm.CreateEncryptor(), CryptoStreamMode.Write))
{
CopyStream(input, encryptedStream);
}
}
 
internal static void DecryptFile(string inputPath, string outputPath, string password)
{
var input = new FileStream(inputPath, FileMode.Open, FileAccess.Read);
var output = new FileStream(outputPath, FileMode.OpenOrCreate, FileAccess.Write);
 
// Essentially, if you want to use RijndaelManaged as AES you need to make sure that:
// 1.The block size is set to 128 bits
// 2.You are not using CFB mode, or if you are the feedback size is also 128 bits
var algorithm = new RijndaelManaged {KeySize = 256, BlockSize = 128};
var key = new Rfc2898DeriveBytes(password, Encoding.ASCII.GetBytes(Salt));
 
algorithm.Key = key.GetBytes(algorithm.KeySize/8);
algorithm.IV = key.GetBytes(algorithm.BlockSize/8);
 
try
{
using (var decryptedStream = new CryptoStream(output, algorithm.CreateDecryptor(), CryptoStreamMode.Write))
{
CopyStream(input, decryptedStream);
}
}
catch (CryptographicException)
{
throw new InvalidDataException("Please supply a correct password");
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
}
 
private static void CopyStream(Stream input, Stream output)
{
using (output)
using (input)
{
byte[] buffer = new byte[SizeOfBuffer];
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, read);
}
}
}
}
}

If you have found this post useful, please take the time to rate this post by clicking on the stars for this blog post, or to say thanks in the comments.

You can download source code for the AesApp here.

ItemsControl Performance Improvements in .NET 4.5


WPF is Slow

One of the most common complaints from C++ or Windows Forms developers moving to WPF/XAML is the issue of performance. I have worked exclusively and intricately with WPF/XAML for the last 4 years and at times have come across performance issues that put me in a corner, including;

  • I needed to enumerate all the alarm and safety devices in an Airports security system inventory. This included fire, smoke, travelator, escalator, motion detection etc. in effect I needed to load up thousands of hardware devices into the WPF application for configuration
  • I was dealing with scientific data for DNA, RNA and Protein. Typically you would have an image with an electropherogram attached to it, which contains thousands of points of floating point data. Scientists required the ability to step through several different samples quickly in order to perform analysis on this data.
    In both these applications, I ended up having to make significant compromises, including using a Windows Forms chart in the scientific application as loading thousands of floating point data into the plethora of commercial and open source WPF charts we tried was unbearably slow. The Windows Forms chart would render the data in milliseconds, where WPF would take a minimum of 10 or 20 seconds with the same data-set, and given the fact that we needed to extend the chart with additional functionality, it added several months worth of development to alter the Windows Forms chart, where it would have been far easier and less time consuming using WPF.

    Staggering

    It turns out that peoples cries about the sluggish nature of WPF applications are correct. Microsoft have managed to attain simply staggering performance improvements to the ItemsControl in WPF. An ItemsControl represents a control that can be used to present a collection of items. In WPF, this includes the TreeView, ListBox, ListView and DataGrid controls that are built using ItemsControls.

DotNet4

In .NET 4 (Visual Studio 2010) and previous, a test was conducted where 12 000 items are loaded into an ItemsControl, the results are in the image below

OutOfMemory

After about 7 minutes, the computer throws an out of memory exception, which I am sure you will agree is absolutely terrible. Microsoft prioritised this issue and in the first iteration managed to increase the total number of items loaded to 200 000 (from 12 000) and load these in 24.5 seconds, an incredible improvement.

FirstIteration

The Pièce de résistance is that they continued to try and get this already considerable metric down even further, in the end  they got this down to 2.3 seconds.

Final

If you have a WPF application that is data centric, especially handling thousands of rows of data, then upgrading to .NET 4.5 is an absolute no brainer. WPF is now at least 182 times quicker whilst handling 16 times more data.

It means that WPF is going to be significantly faster with the additional improvements that have been made to virtualisation in ItemsControls and Cold/Warm start-up times for .NET applications in general.

Calculate range/limit with C#


A recurring requirement in every day programming is determining whether a value exists with a certain range. Since it is exam time (for most students at present), I resolved to write a quick application demonstrating this requirement based around examination marks.

This quick demo is written in WPF, but should work in Silverlight or Windows Phone 7 with no alteration. The Range class though, can be used throughout .NET in general.

To start with, create a new WPF application in visual Studio and call it ExamApp. Add a new folder to the project called Range and in this declare a new interface called IRange with the following members

using System;
 
namespace ExamApp.Range
{
public interface IRange<T> where T : IComparable<T>
{
T Start { get; }
T End { get; }
bool InRange(T valueToFind);
}
}

Create a new class in the same folder called Range which implements the interface above

using System;
 
namespace ExamApp.Range
{
public class Range<T> : IRange<T> where T : IComparable<T>
{
private readonly T start;
private readonly T end;
 
public Range(T start, T end)
{
if (start.CompareTo(end) <= 0)
{
this.start = start;
this.end = end;
}
else
{
this.start = end;
this.end = start;
}
}
 
public T Start
{
get { return this.start; }
}
 
public T End
{
get { return this.end; }
}
 
public bool InRange(T valueToFind)
{
return valueToFind.CompareTo(Start) >= 0 && valueToFind.CompareTo(End) <= 0;
}
}
}
 

Add a new Folder to the project called Examinations and in this add a new class called Percentage. This Percentage class inherits off Range, and here you can create whatever logical range class you may desire for your own applications

using System;

using ExamApp.Range;
 
namespace ExamApp.Examinations
{
public class Percentage<T> : Range<T> where T : IComparable<T>
{
public Percentage(T start, T end) : base(start, end)
{
}
}
}
 

Add a new enumeration called Grade thus

namespace ExamApp.Examinations

{
public enum Grade
{
None = 0,
A = 1,
B = 2,
C = 3,
D = 4,
E = 5,
} ;
}
 

Add a new interface called ITest with the following members.

namespace ExamApp.Examinations

{
interface ITest
{
int ArtAndDesignMark { get; set; }
int ScienceMark { get; set; }
int MathsMark { get; set; }
}
}
 

Add a new folder called Converters to the project, and add the following

using System;

using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows.Data;
using System.Windows.Markup;
using ExamApp.Examinations;
 
namespace ExamApp.Converters
{
public class MarkToGradeConverter : MarkupExtension, IValueConverter
{
private static MarkToGradeConverter instance;
private static readonly Dictionary<Percentage<int>, Grade> Marks;
 
static MarkToGradeConverter()
{
Marks = new Dictionary<Percentage<int>, Grade>
{
{new Percentage<int>(80, 100), Grade.A},
{new Percentage<int>(75, 79), Grade.B},
{new Percentage<int>(60, 74), Grade.C},
{new Percentage<int>(55, 59), Grade.D},
{new Percentage<int>(0, 54), Grade.E},
};
}
 
public override object ProvideValue(IServiceProvider serviceProvider)
{
return instance ?? (instance = new MarkToGradeConverter());
}
 
#region Implementation of IValueConverter
 
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return GetGrade((int)value).ToString();
}
 
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
 
public static Grade GetGrade(int mark)
{
Percentage<int> key = Marks.Keys.FirstOrDefault(r => r.InRange(mark));
 
if (key != null)
{
Grade grade;
 
if (Marks.TryGetValue(key, out grade))
{
return grade;
}
}
return Grade.None;
}
 
#endregion
}
}
 

As you can see most of the logic is executed here. Add a new class to the project called Student with the following properties. Also note that this implements the ITest interface that was declared earlier

using ExamApp.Examinations;

 
namespace ExamApp
{
public class Student : ITest
{
public Student(string firstName, string surname, int artAndDesignMark, int scienceMark, int mathsMark)
{
this.FirstName = firstName;
this.Surname = surname;
this.ArtAndDesignMark = artAndDesignMark;
this.ScienceMark = scienceMark;
this.MathsMark = mathsMark;
}
 
public Student()
{
}
 
public string FirstName { get; set; }
public string Surname { get; set; }
 
#region Implementation of ITest
 
public int ArtAndDesignMark { get; set; }
public int ScienceMark { get; set; }
public int MathsMark { get; set; }
 
#endregion
 
}
}
 

We need a collection of students to show in a list so create the following class that inherits off ObservableCollection<T>

using System.Collections.ObjectModel;

namespace ExamApp
{
public class Students : ObservableCollection<Student>
{
public Students()
{
Add(new Student
{
FirstName = "John",
Surname = "Lennon",
ArtAndDesignMark = 81,
ScienceMark = 59,
MathsMark = 77
});
Add(new Student
{
FirstName = "Paul",
Surname = "McCartney",
ArtAndDesignMark = 88,
ScienceMark = 40,
MathsMark = 66
});
Add(new Student
{
FirstName = "Ringo",
Surname = "Starr",
ArtAndDesignMark = 88,
ScienceMark = 31,
MathsMark = 96
});
Add(new Student
{
FirstName = "George",
Surname = "Harrison",
ArtAndDesignMark = 100,
ScienceMark = 99,
MathsMark = 99
});
 
}
}
}
 

Now the data structures are complete, add the following .xaml markup

<Window x:Class="ExamApp.MainWindow"
xmlns:Converters="clr-namespace:ExamApp.Converters"
Title="MainWindow"
Width="525"
Height="350">
<Window.Resources>
<Converters:MarkToGradeConverter x:Key="MarkToGradeConverter" />
</Window.Resources>
<ListView x:Name="studentsListBox">
<ListView.View>
<GridView>
<GridViewColumn Width="120"
DisplayMemberBinding="{Binding Path=FirstName}"
Header="Name" />
<GridViewColumn Width="120"
DisplayMemberBinding="{Binding Path=Surname}"
Header="Surname" />
<GridViewColumn Width="40"
DisplayMemberBinding="{Binding Path=ArtAndDesignMark,
Converter={StaticResource MarkToGradeConverter}}"
Header="Art" />
<GridViewColumn Width="60"
DisplayMemberBinding="{Binding Path=ScienceMark,
Converter={StaticResource MarkToGradeConverter}}"
Header="Science" />
<GridViewColumn Width="50"
DisplayMemberBinding="{Binding Path=MathsMark,
Converter={StaticResource MarkToGradeConverter}}"
Header="Maths" />
</GridView>
</ListView.View>
 
</ListView>
 
</Window>
 

Add the following code to the constructor of the main window

using System.Windows;
 
namespace ExamApp
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.studentsListBox.ItemsSource = new Students();
}
}
}
 

You should have the following

Students

As you can see it is quite a simple and pretty reusable way to use ranges in your application.

The source code for this simple example is available here

Zoomable autosizing canvas in WPF


I have created a control for a project I am working on that uses a canvas to draw graph ticks for a custom scale, but ran into the limitation of the canvas control where child items are not scaled accordingly when the height (or width) of the canvas changes. Luckily, this is quite a straightforward problem to fix, but I just could not seem to find either the correct search terms to enter in Google or locating code samples in books that demonstrated how to resolve the issue. I have just knocked this code up this afternoon so it is not perfect, but should suffice should you require something similar.

Small

Large

In order to resolve the problem you will need to create a custom canvas and override both MeasureOverride and ArrangeOveride incorporating any custom logic you require in these methods.

using System.Windows;
using System.Windows.Controls;
using System.Windows.Shapes;
 
namespace AutosizingCanvasApp.Controls
{
public class TickCanvas : Canvas
{
// Vertical axis where the X value is never changed
private const double X = 0;
private Size initialSize;
 
// Override the default Measure method of Panel
protected override Size MeasureOverride(Size availableSize)
{
var canvasDesiredSize = new Size();
 
// In our example, we just have one child.
// Report that our canvas requires just the size of its only child.
 
foreach (UIElement child in InternalChildren)
{
child.Measure(availableSize);
canvasDesiredSize = child.DesiredSize;
}
 
return canvasDesiredSize;
}
 
protected override Size ArrangeOverride(Size finalSize)
{
if (initialSize.Height == 0)
{
initialSize = finalSize;
}
var ratio = finalSize.Height / initialSize.Height;
 
for (int index = 0; index < this.InternalChildren.Count; index++)
{
UIElement child = this.InternalChildren[index];
 
double y = ((Line)child).Y1;
 
child.Arrange(finalSize.Height > initialSize.Height
? new Rect(new Point(X, (ratio * y) – y), child.DesiredSize)
: new Rect(new Point(X, 0), child.DesiredSize));
}
return finalSize; // Returns the final Arranged size
}
}
}

In the .xaml I have a border with the custom canvas as a child that have some Line objects all affecting the Y axis position.

<Window x:Class="AutosizingCanvasApp.MainWindow"
xmlns:controls="clr-namespace:AutosizingCanvasApp.Controls"
xmlns:local="clr-namespace:AutosizingCanvasApp.Converters"
Title="mainWindow"
Width="300"
Height="768"
WindowStartupLocation="CenterScreen">
<Window.Resources>
<local:BorderHeightValueConverter x:Key="BorderHeightValueConverter" />
<local:LinePositionConverter x:Key="LinePositionConverter" />
</Window.Resources>
 
<Border x:Name="mainBorder"
Width="94"
Height="{Binding ElementName=mainWindow,
Path=ActualHeight,
Converter={StaticResource BorderHeightValueConverter}}"
Margin="50"
BorderBrush="Black"
BorderThickness="2"
ToolTip="{Binding ElementName=mainBorder,
Path=ActualHeight}">
<controls:TickCanvas x:Name="myCanvas">
<Line x:Name="line1"
Stroke="Red"
StrokeThickness="2"
ToolTip="{Binding ElementName=line1,
Path=Y1}"
X1="0"
X2="60"
Y1="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.2}"
Y2="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.2}" />
<Line x:Name="line2"
Stroke="Blue"
StrokeThickness="2"
ToolTip="{Binding ElementName=line2,
Path=Y1}"
X1="0"
X2="60"
Y1="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.4}"
Y2="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.4}" />
<Line x:Name="line3"
Stroke="Green"
StrokeThickness="2"
ToolTip="{Binding ElementName=line3,
Path=Y1}"
X1="0"
X2="60"
Y1="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.6}"
Y2="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.6}" />
<Line x:Name="line4"
Stroke="Purple"
StrokeThickness="2"
ToolTip="{Binding ElementName=line4,
Path=Y1}"
X1="0"
X2="60"
Y1="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.8}"
Y2="{Binding ElementName=mainBorder,
Path=ActualHeight,
Converter={StaticResource LinePositionConverter},
ConverterParameter=0.8}" />
</controls:TickCanvas>
</Border>
</Window>

I also have a couple of converters that converts the height of the border as that changes when you resize the parent window and a couple of converters that reposition the line objects in the canvas. Be aware that the border itself has a thickness, so you will need to incorporate that in any sizing but has been omitted here so the lines may be a couple of pixels off.

using System;
using System.Globalization;
using System.Windows.Data;
 
namespace AutosizingCanvasApp.Converters
{
public class LinePositionConverter : IValueConverter
{
#region Implementation of IValueConverter
 
/// <summary>
/// Converts a value.
/// </summary>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return ((double) value)*double.Parse(parameter.ToString());
}
 
/// <summary>
/// Converts a value.
/// </summary>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
/// <param name="value">The value that is produced by the binding target.</param><param name="targetType">The type to convert to.</param><param name="parameter">The converter parameter to use.</param><param name="culture">The culture to use in the converter.</param>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
 
#endregion
}
}

using System;
using System.Globalization;
using System.Windows.Data;
 
namespace AutosizingCanvasApp.Converters
{
public class BorderHeightValueConverter : IValueConverter
{
#region Implementation of IValueConverter
 
/// <summary>
/// Converts a value.
/// </summary>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
/// <param name="value">The value produced by the binding source.</param>
/// <param name="targetType">The type of the binding target property.</param>
/// <param name="parameter">The converter parameter to use.</param>
/// <param name="culture">The culture to use in the converter.</param>
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
return (((double)value)*0.7);
}
 
/// <summary>
/// Converts a value.
/// </summary>
/// <returns>
/// A converted value. If the method returns null, the valid null value is used.
/// </returns>
/// <param name="value">The value that is produced by the binding target.</param><param name="targetType">The type to convert to.</param><param name="parameter">The converter parameter to use.</param><param name="culture">The culture to use in the converter.</param>
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
 
#endregion
}
}
 

The source code is for this example is available here.