Visual inheritance in WPF

My final year .NET project was a medium-weight WPF application which had some 8 windows in all. Creating the windows and customizing the interface in XAML was a breeze with Visual Studio 2008 and Expression Blend 2. Even coding up the window logic was not that tough, but halfway into the logic part, I realized that all my windows had some properties and methods in common. So the code could be shortened a great deal using inheritance.

Basically, the approach is simple. Create a class in a separate code file (say Blindow in Blindow.cs) which inherits from System.Windows.Window, add all the properties and method implementations and virtual methods you need to it, and make all your windows inherit from Blindow. So, our Blindow looks like this:

  1. namespace BlindApp.Windows
  2. {
  3. public class Blindow : Window
  4. {
  5. // all your properties and methods here
  6. }
  7. }

So, the class declarations for all the windows in the application now change from

public partial class Window1 : Window

public partial class Window1 : Blindow

All is fine and well, the code should compile correctly, but shockingly, it doesn't and throws up an error. Reason: Forgot the XAML. If you know WPF well, you must realize that the class declaration for Window1 in the codebehind is only partial. The remaining partial declaration lies in the XAML. So, this means one has to come up with a way to let XAML know that Window1 inherits from Blindow now.
The source of the error now lies here

<Window x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

So what we need to do to rectify the error is first add an XML namespace (with any name you like) for the CLR namespace. The CLR namespace for Window1 is BlindApp.Windows, so add a line as follows

<Window x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

You don't need to type out the clr-namespace: statement - Visual Studio 2008 provides IntelliSense for that. But, we are not done yet, an error will again pop up because we need to replace the first line itself. Now that the XML namespace has been created, this is how it's done:

<blinder:Blindow x:Class="BlindApp.Windows.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

Just like you could set Resources and Triggers with Window.Resources and Window.Triggers, you can do the same now with <blinder:blindow.resources> and <blinder:blindow.triggers>


MD5 and TripleDES encryption in .NET

The .NET Framework provides classes for MD5 hashing and TripleDES encryption, both of which, when used together with a good enough key, form a good cryptographic system for your application. There are a lot of scenarios one can think of where encryption can be put to good use in both Desktop and Web applications. The following code snippet provides functions for encryption and decryption using MD5 and TripleDES.

What you need to include in the usings list is System.Security.Cryptography and System.Text and you are good to go. Making the functions static is just one of the best practices.

  1. public class Utils
  2. {
  3. public static string Encrypt(string toEncrypt, string key, bool useHashing)
  4. {
  5. // Convert both strings to byte arrays - you can use encoding other than UTF8
  6. byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
  7. byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);
  8. if (useHashing)
  9. {
  10. // Hash the key
  11. MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
  12. keyArray = hashmd5.ComputeHash(keyArray);
  13. hashmd5.Clear();
  14. }
  15. TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider
  16. {
  17. Key = keyArray,
  18. // The following line is controversial - follow the link below the snippet
  19. Mode = CipherMode.ECB,
  20. Padding = PaddingMode.PKCS7
  21. };
  22. ICryptoTransform cTransform = tdes.CreateEncryptor();
  23. // Transform and store in resultArray
  24. byte[] resultArray = cTransform.TransformFinalBlock(toEncryptArray, 0, toEncryptArray.Length);
  25. tdes.Clear();
  26. return Convert.ToBase64String(resultArray, 0, resultArray.Length);
  27. }
  28. public static string Decrypt(string toDecrypt, string key, bool useHashing)
  29. {
  30. byte[] keyArray = UTF8Encoding.UTF8.GetBytes(key);
  31. byte[] toDecryptArray = Convert.FromBase64String(toDecrypt);

  32. if (useHashing)
  33. {
  34. MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
  35. keyArray = hashmd5.ComputeHash(keyArray);
  36. hashmd5.Clear();
  37. }
  38. TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider
  39. {
  40. Key = keyArray,
  41. Mode = CipherMode.ECB,
  42. Padding = PaddingMode.PKCS7
  43. };

  44. ICryptoTransform cTransform = tdes.CreateDecryptor();
  45. byte[] resultArray = cTransform.TransformFinalBlock(toDecryptArray, 0, toDecryptArray.Length);
  46. tdes.Clear();
  47. return UTF8Encoding.UTF8.GetString(resultArray);
  48. }
  49. }

FYI, here is the controversy.
As you can see, both functions are quite similar except for precisely 2 lines. The Clear() function on both occasions are required because MD5CryptoServiceProvider and TripleDESCryptoServiceProvider classes are "managed wrappers around unmanaged resources". Putting the Encrypt and Decrypt functions to use in your application would look like this:

  1. string encrypted = Utils.Encrypt("Password", "Key", true);
  2. string original = Utils.Decrypt(encrypted, "Key", true);

Just make sure that you use the same key in both the lines, wherever the lines may be (they may be in two different applications referencing a common dll containing these functions) and the same hashing parameter as well. Happy encryption!