Click here to Skip to main content
Click here to Skip to main content

Generic Support In XAML

, 17 Jun 2009
Rate this:
Please Sign up or sign in to vote.
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 do actually enable WPF developers the correct mechanisms

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 do 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.

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 its 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 the small demo app genericviews.zip, that creates a generic window with a MessageBoxLogger, and when run looks like this:

image-thumb.png

Enjoy

NOTE:

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

http://blogs.msdn.com/mikehillberg/archive/2006/10/06/LimitedGenericsSupportInXaml.aspx

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Sacha Barber
Software Developer (Senior)
United Kingdom United Kingdom
I currently hold the following qualifications (amongst others, I also studied Music Technology and Electronics, for my sins)
 
- MSc (Passed with distinctions), in Information Technology for E-Commerce
- BSc Hons (1st class) in Computer Science & Artificial Intelligence
 
Both of these at Sussex University UK.
 
Award(s)

I am lucky enough to have won a few awards for Zany Crazy code articles over the years

  • Microsoft C# MVP 2014
  • Codeproject MVP 2014
  • Microsoft C# MVP 2013
  • Codeproject MVP 2013
  • Microsoft C# MVP 2012
  • Codeproject MVP 2012
  • Microsoft C# MVP 2011
  • Codeproject MVP 2011
  • Microsoft C# MVP 2010
  • Codeproject MVP 2010
  • Microsoft C# MVP 2009
  • Codeproject MVP 2009
  • Microsoft C# MVP 2008
  • Codeproject MVP 2008
  • And numerous codeproject awards which you can see over at my blog

Comments and Discussions

 
GeneralIt is for root element ONLY PinmemberMaciej Pilichowski10-Sep-10 5:15 
GeneralRe: It is for root element ONLY PinmvpSacha Barber10-Sep-10 5:17 
QuestionHow did I miss it? PinmentorKunalChowdhury26-Aug-10 23:05 
AnswerRe: How did I miss it? PinmvpSacha Barber26-Aug-10 23:42 
GeneralRe: How did I miss it? PinmentorKunalChowdhury27-Aug-10 0:34 
GeneralRe: How did I miss it? PinmvpSacha Barber27-Aug-10 0:49 
QuestionAlmost same problem with different namespaces of base Classes and Generic type Need Help!!! PinmemberSalman Mustansar28-Jul-10 0:32 
AnswerRe: Almost same problem with different namespaces of base Classes and Generic type Need Help!!! PinmvpSacha Barber28-Jul-10 0:52 
GeneralExactly what I was looking for PinmemberPHDENG8124-Jul-09 10:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140709.1 | Last Updated 17 Jun 2009
Article Copyright 2009 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid