Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Generic Support In XAML

0.00/5 (No votes)
17 Jun 2009 1  
Generic support in XAML

I have worked with XAML/WPF for a while now, but it wasn’t until recently I thought about generic support in XAML. I had no idea if it was possible, so I decided to have a quick look into this.

Luckily, the WPF team thought about this and did actually enable WPF developers the correct mechanisms to fully support generics from within XAML.

The first thing you need to know is that a typical WPF window is made up of 2 partial classes, the code behind and the XAML, then at compilation time, a combined file known as the generated file is formed with the combination of the code behind file and the XAML file.

37317/build-thumb.jpg

So in order to correctly support generics for a file that is made up of both code behind and XAML, we MUST ensure that both parts of the file are using generic type arguments. This should become clearer as we move on to see a small example.

In order to demonstrate the support for generics in XAML, let us consider a small example, which requires the following arrangement:

  1. We have a common window base class that is generic
  2. We inherit from the common window base class, but we then need to provide generic arguments within the code behind and the XAML in order to make it a generic type.

That’s basically what we are trying to do. In order to demonstrate this, I have constructed a small demo app that carries out the following:

I have an abstract base class called LoggingStrategy which looks like this:

1:  using System;
2:
3:  namespace GenericViews
4:  {
5:      public abstract class LoggingStrategy
6:      {
7:          public abstract void LogText(string textToLog);
8:      }
9:  }

I then have a specific class that overrides the LogText(…) method, this is as follows:

 1:  using System;
 2:  using System.Windows;
 3:
 4:  namespace GenericViews
 5:  {
 6:      public class MessageBoxLogger : LoggingStrategy
 7:      {
 8:          public override void LogText(string textToLog)
 9:          {
10:              MessageBox.Show(textToLog);
11:          }
12:      }
13:  }

Then within the main App class that you get, if you start a new WPF application in VS2008, I have created a simple Dictionary lookup for a Type to get the correct logging strategy to use. The idea being that the Type will come from a generic argument provided by the view, as we will see in just a minute.

For now, all you need to know is that there is a lookup against a Type that returns a LoggingStrategy inherited object.

 1:  using System;
 2:  using System.Collections.Generic;
 3:  using System.Windows;
 4:
 5:  namespace GenericViews
 6:  {
 7:      public partial class App : Application
 8:      {
 9:          public static Dictionary<Type, LoggingStrategy> Loggers =
10:              new Dictionary<Type, LoggingStrategy>();
11:
12:
13:          static App()
14:          {
15:              Loggers.Add(typeof(MessageBoxLogger), new MessageBoxLogger());
16:          }
17:      }
18:  }

So we have pretty much covered all the demo stuff, now it's just a question of dealing with the actual generic stuff. In the attached demo, I have provided a small base class for views, and the base class is generic, and will lookup the correct LoggingStrategy inherited object, from the Dictionary stored in the static App Dictionary.

Here is the base class for the views.

 1:  using System;
 2:  using System.Collections.Generic;
 3:  using System.Windows;
 4:
 5:  namespace GenericViews
 6:  {
 7:      public class ViewBase<T> : Window where T : LoggingStrategy
 8:      {
 9:          public LoggingStrategy CurrentLogger { get; private set; }
10:
11:          public ViewBase()
12:          {
13:              CurrentLogger = App.Loggers[typeof(T)];
14:          }
15:      }
16:  }

It can be seen that this base class expects a generic argument T in order to work. T must inherit from LoggingStrategy. What then happens is generic argument is used to obtain the correct LoggingStrategy inherited object from the Dictionary stored in the static App Dictionary.

Ok we are nearly there, all we now have to do is make a custom window which inherits from the ViewBase<T>, and passes a generic argument.

Let’s start with the easy part, the code behind. This part is dead easy, we simply use standard generic stuff, as we would any other generic class:

 1:  using System;
 2:  using System.Collections.Generic;
 3:  using System.Windows;
 4:
 5:
 6:  namespace GenericViews
 7:  {
 8:
 9:      public partial class MessageLoggingWindow : ViewBase<MessageBoxLogger>
10:      {
11:          public MessageLoggingWindow() : base()
12:          {
13:              InitializeComponent();
14:          }
15:
16:          private void Button_Click(object sender, RoutedEventArgs e)
17:          {
18:              base.CurrentLogger.LogText(
19:                  String.Format("Sometext which was logged at {0}",
20:                  DateTime.Now.ToShortTimeString()));
21:          }
22:      }
23:  }

Now that the easy part is done, why don’t we focus our efforts on the XAML part.

1:  <local:ViewBase
2:      x:Class="GenericViews.MessageLoggingWindow"
3:      x:TypeArguments="local:MessageBoxLogger"
4:      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
5:      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
6:      xmlns:local="clr-namespace:GenericViews">
7:  …
8:  …
9:  </local:ViewBase>

Now, what is going on here exactly. Well a couple of things actually, let’s go through them.

  1. x:Class: That’s the name of the class, this matches the code behind namespace and class name
  2. xmlns:local: This is a namespace alias that allows use to use local: in the XAML to point to classes in the GenericViews namespace
  3. <local:ViewBase…/>: Means we are using GenericViews.ViewBase<T> as the base class for this new Window, but wait what about the generic argument. Well that’s step 4.
  4. x:TypeArguments: This is where the generic value gets plugged in. So we now have a window declared in XAML which is really GenericViews.ViewBase<MessageBoxLogger>

That’s it…..I know my example is not exactly real world, but that was not the point of all this, I simply wanted to show you how to create generics in XAML, and to that end, this post should do just that.

Here is a small demo app, that creates a generic window with a MessageBoxLogger, and when run looks like this:

37317/image-thumb.png

Enjoy!

NOTE

A reader of this blog also pointed me to another entry by Mike Hillberg, which covers a lot of other generic support in XAML, have a look here for that, it's quite cool.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here