Click here to Skip to main content
6,822,123 members and growing! (19,597 online)
Email Password   helpLost your password?
Languages » C# » General     Intermediate License: The Code Project Open License (CPOL)

DI/IOCs

By Sacha Barber

A look at Dependency Injection and IOC containers
C# (C#2.0, C#3.0), .NET (.NET2.0, .NET3.0, .NET3.5), WPF, WinForms, Architect, Dev
Posted:2 Jan 2009
Views:11,898
Bookmarked:53 times
Unedited contribution
printPrint   add Share
      Discuss Discuss   Broken Article?Report  
15 votes for this article.
Popularity: 5.39 Rating: 4.58 out of 5

1

2
2 votes, 13.3%
3
3 votes, 20.0%
4
10 votes, 66.7%
5

Introduction

At the place where I work we have started developing a new project using all sorts of Agile/SCRUM/Xp methodologies, and we were actually lucky enough to have Martin Fowlers company: ThoughtWorks, come in and teach us a few things. One of these things was Dependency Injection. Now there are already a number of articles here at codeproject about DI, but after reading a few of them I felt there was still room for another one, as I wanted to talk a little bit about what is trying to solve, which is something that some of the other articles didn't seem to cover.

What IOCs Solve

Typically when we write software we are writing software that calls on service classes, not nessecarily web services, what I mean are classes that provide some function when called, consider the following code, where I am expecting to be able to use some sort of logging service and some sort of exception reporting service.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication1
{
    public class SomeClass
    {
        private ILoggingStrategy logger = null;
        private IExceptionReporter exreporter = null;

        public SomeClass()
        {
		      //create a SQL logger
            logger = new SQLLogger();
        }


        public void SomeMethod()
        {
            //create a SQL Exception reporter
            exreporter = new SQLExceptionReporter();
        }
    }
}

More often that not if an object needs to gain access to a certain service, the actual object takes on the role of creating an instance of the service (as seen above) that the code needs. This can take many forms it could be done in a constructor or by holding a direct reference to a service object, or could even use some sort of service locator to provide an instance of a particular service object. What all these approaches are doing is holding references of service objects within the consuming object, which strongly ties the consuming object to the instance of the service objects, which may not be desirable, as the consumer now depends on the service objects.

What Dependency Injection does, is allow this dependency on service classes to be inverted, so they are no longer created in the consuming object.

DI can either use a property or constructor parameters, which must be of the desired service types, and when the object that needs these service types, is created, an implementation of the desired service type is automatically passed to the object being consructed by some external mechanism. Bingo no more internal dependencies on service types within the consuming object.

Dependency Injection is more flexable that holding internal references, as it allows an alternative implemention of a given service to be created and literally injected into the object that requires the service type. The actual service implementaion type may be configured in a config file, so one could easily swap out one service type implementation for another. Imagine a situation where you have written some software that needs to work with SQL and then your company decides you must also support Oracle, if we use DI and config files, we could configure the solution to hold either a Oracle service type or a SQL service type and the code that utilises these services could work without being recompiled.

Another area where DI is especially useful is when using Mocks, you can use a Mock service type by simply setting the config file to point at a Mock implementation of some service, this is very useful. We have actually done just this at work, and it allows us a lot of flexability with our Unit/Integration tests.

Obviously with this level of configurability, comes what is known as explosion of interfaces, so DI also has it's own drawn backs. However, the benefits that DI can bring could easily outway the number of interfaces that you will wind up working with. Obviously there should be a valid and just reason to use DI, it's worth having a think about though.

There are a few good DI implementations out there, which allow the configuration of types to be done via config files/special attributes. Generally these frameworks all offer DI under the umbrella name of IOC which stands for "Inversion of control".

According to WikiPedia IOC is

"Inversion of Control, or IoC, is an abstract principle describing an aspect of some software architecture designs in which the flow of control of a system is inverted in comparison to the traditional architecture of software libraries."

Pretty much most (if not all) of the IOC frameworks out there simply act as containers for service types. You can think of the container as a special/clever dictionary that knows how to grab a service type and provide it when needed. The basic idea is that you have a container that knows about all the service types (or other types you wish to use with DI). The IOC framework will inject these service types when an object that requires one of these known/stored (in the container) service types need one.

In the remainder of this article I will talk about how to do DI using some of the free frameworks out there, and at the end of the article I will provide links to more DI/IOC frameworks that you may choose to investigate by yourself.

The Common Demo Code Example

The attached demo code contains 3 projects:

  • CastleWindsorIOC : Shows how to work with constructor DI and generics support
  • UnityIOC : Shows how to work with constructor DI and generics support
  • UnityIOCPropertyResolution : Shows how to work with property DI

Both the CastleWindsorIOC and the UnityIOC projects set out to demonstrate exactly the same problem. The problem that they are setting out to demonstrate are quite simple. There is a single interface called IMessageFormatter which has 2 implementations DateTimeMessageFormatter and SimpleMessageFormatter which can be used by providing the correct settings in the config file.

There is also an example of how to work with a IGenericFormatter<T> generic interface, where the implementation is done in an class called DummyObjectFormatter.

There is also a simple Form (Form1) object that requires a IMessageFormatter and a IGenericFormatter<DummyObject> implementation passed into the constructor in order to work correctly.

This may become clearer if I show you a class diagram.

Castle Windsor Container

The Castle Windsor container is part of the Castle project, and can be downloaded at http://www.castleproject.org/

The basic idea behind using Castle Windsor container is that you have a container that can be configured though code/config files.

Castle Windsor Container : Config

I like to work to with a config file as it offers the greatest level of flexibility as we can literally alter the config file without the need to recompile the code.

Here is an example config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <!-- Custom Config Sections -->
  <configSections>
    <section
        name="castle"
        type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
  </configSections>


  <!-- Castle Config Section -->
  <castle>
    <components>

      <!-- Alternative Message Provider 
          
      <component
        id="CurrentFormatter"
        service="CastleWindsorIOC.IMessageFormatter, CastleWindsorIOC"
        type="CastleWindsorIOC.SimpleMessageFormatter, CastleWindsorIOC" />
          
      -->

      <component
        id="CurrentFormatter"
        service="CastleWindsorIOC.IMessageFormatter, CastleWindsorIOC"
        type="CastleWindsorIOC.DateTimeMessageFormatter, CastleWindsorIOC" />

      <component id="DummyObjectFormatter"
                 service="CastleWindsorIOC.IGenericFormatter`1[[CastleWindsorIOC.DummyObject, 
					CastleWindsorIOC]], CastleWindsorIOC"
                 type="CastleWindsorIOC.DummyObjectFormatter, CastleWindsorIOC"/>

    </components>
  </castle>

</configuration>

It can be seen that we simply create a custom Castle config section, and in that custom Castle section we configure the container to tell it what types it should be able to resolve. This is done via a new component element per type that is required.

We can see that this config files have 2 types (one if commented out, which you could uncomment to try it out, but don't forget to comment the current one if you want to try the currently commented one) which are 2 different implementations of the same IMessageFormatter interface, thus effectively providing 2 different services, albeit very simple services in this case.

Castle Windsor Container : Constructor Support

As you saw from the class diagram above there is a IMessageFormatter interface that has 2 different implementations (SimpleMessageFormatter and DateTimeMessageFormatter). The config file that you just saw shows how to add these types to the Castle Windsor container.

So how do we go about using one of these types from the Castle Windsor container, well that's fairly simple, we just do something like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using Castle.Core.Resource;


namespace CastleWindsorIOC
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            IWindsorContainer container =
                new WindsorContainer(
                    new XmlInterpreter(new ConfigResource("castle")));

            // use the Current Message Formatter (see the App.Config)
            var currentIMessageFormatter =
                (IMessageFormatter)container.Resolve("CurrentFormatter");

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1(currentIMessageFormatter));
        }
    }
}

It can be seen from this example that we are firstly configuring the Castle Windsor container and then we are obtaining all the types we need from the container and then constructing a new Form1 object and passing these container objects to the constructor of the Form1 object.

Lets have a look at the Form1 code.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;


namespace CastleWindsorIOC
{
    public partial class Form1 : Form
    {
        private IMessageFormatter msgFormatter;
        private int currentMessageCount = 0;

        public Form1()
        {
            InitializeComponent();
        }

        public Form1(IMessageFormatter msgFormatter)
            : this()
        {
            this.msgFormatter = msgFormatter;
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            lstItems.Items.Add(msgFormatter.FormatMessage(
                String.Format("CurrentMessage {0}",
                currentMessageCount++)));
        }

		.....
		.....
    }
}

From here we can see that the types that the Form1 object needs for its constructor have been resolved by the Castle Windsor container and supplied to the Form1 constructor. Cool.

So what happens when we run the app, we get a message formatted using the current (App.Config type that is use) IMessageFormatter interface implementation.

Castle Windsor Container : Generics Support

So that's cool, we now have DI working with constructor parameters using the Castle Windsor container. So what else can we do, surely there is more. Well yeah there is actually. We can actually use DI with generics. Here is an example of how to do this.

The demo code has an IGenericFormatter<T> interface which is declared like this

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CastleWindsorIOC
{
    public interface IGenericFormatter<T>
    {
        String FormatMessage(T valueIn);
    }
}

Where the demo code also contain an implementation of this interface as follows:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CastleWindsorIOC
{
    public class DummyObjectFormatter : IGenericFormatter<DummyObject>
    {

        public string FormatMessage(DummyObject valueIn)
        {
            return String.Format("The value was {0}", valueIn.ToString());
        }

    }
}

Here is what you need to do for the App.Config file to support generics.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <!-- Custom Config Sections -->
  <configSections>
    <section
        name="castle"
        type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
  </configSections>


  <!-- Castle Config Section -->
  <castle>
    <components>

      <!-- Alternative Message Provider 
          
      <component
        id="CurrentFormatter"
        service="CastleWindsorIOC.IMessageFormatter, CastleWindsorIOC"
        type="CastleWindsorIOC.SimpleMessageFormatter, CastleWindsorIOC" />
          
      -->

      <component
        id="CurrentFormatter"
        service="CastleWindsorIOC.IMessageFormatter, CastleWindsorIOC"
        type="CastleWindsorIOC.DateTimeMessageFormatter, CastleWindsorIOC" />

      <component id="DummyObjectFormatter"
                 service="CastleWindsorIOC.IGenericFormatter`1[[CastleWindsorIOC.DummyObject, 
				 	CastleWindsorIOC]], CastleWindsorIOC"
                 type="CastleWindsorIOC.DummyObjectFormatter, CastleWindsorIOC"/>

    </components>
  </castle>

</configuration>

In this case I am using a type of Unity.DummyObject to be the type that is used for the IGenericFormatter<T> implementaion, which if you remember was defined like this.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace CastleWindsorIOC
{
    public class DummyObjectFormatter : 
        IGenericFormatter<DummyObject>
    {

        public string FormatMessage(DummyObject valueIn)
        {
            return String.Format("The value was {0}", 
                valueIn.ToString());
        }

    }
}

So we can see that the DummyObjectFormatter is expecting to be passed a DummyObject from the Castle Windsor container. The config file section I just showed you does just that.

So how do we resolve this using the Castle Windsor container, well we simply do the following:

// use the generic Message Formatter
var dummyObjectFormatter =
    (IGenericFormatter)container.Resolve("DummyObjectFormatter");

And if we examine the constructor of a Form1 object that requires such a type to be provided, it should be pretty obvious that all we need to do is pass the container obtained generic object to the Form1 objects constructor.

public Form1(IMessageFormatter msgFormatter,
    IGenericFormatter actualGenTest)
    : this()
{
    this.msgFormatter = msgFormatter;
    this.actualGenTest = actualGenTest;
}

Castle Windsor Container : Property Support

Is should be possible to not only inject constructor parameters but also to use DI/IOC to inject property values. I had a go of this using the Castle Windsor container, but didn't get any where with it. I am sure it can be done, I just didn't manage it....But like I say I think it is possible.

 

 

Unity Container

Unity is a Microsoft application block offering, from the Patterns & Practices group, and can be downloaded at http://msdn.microsoft.com/en-us/library/dd203101.aspx

The basic idea behind using Unity is that you have a container that can be configured though code/config files, much the same as Castle Windsor. I think the best way to demonstrate this, is by working through the same small example as we did with Castle Windsor above.

So let's do that.

Unity Container : Config

I like to work to with a config file as it offers the greatest level of flexibility as we can literally alter the config file without the need to recompile the code.

Here is an example config file.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <!-- Custom Config Sections -->
  <configSections>
    <section name="unity"
        type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
              Microsoft.Practices.Unity.Configuration" />
  </configSections>

  <!-- Unity Config Section -->
  <unity>
    <containers>
      <container>
        <types>
          
	
	        <!-- Alternative Message Provider 

          &lt;type name="CurrentFormatter" 
              type="Unity.IMessageFormatter,Unity"
              mapTo="Unity.SimpleMessageFormatter,Unity"/&gt;
	        -->
          
          <type name="CurrentFormatter"
              type="Unity.IMessageFormatter,Unity"
              mapTo="Unity.DateTimeMessageFormatter,Unity"/>


        </types>
      </container>
    </containers>
  </unity>

</configuration>

It can be seen that we simply create a custom Unity config section (much the same as Castle Windsor), and in that custom Unity section we configure the container to tell the container which types it will know about at runtime.

We can see that this config files have 2 types (one if commented out, which you could uncomment to try it out, but don't forget to comment the current one if you want to try the currently commented one) which are 2 different implementations of the same IMessageFormatter interface, thus effectively providing 2 different services, albeit very simple services in this case. It should still demonstrate the idea.

Unity Container : Constructor Support

We are using the same example as the Castle Windsor, where we use the same IMessageFormatter interface and have 2 different implementations of this interface (SimpleMessageFormatter and DateTimeMessageFormatter) that we saw in the Castle Windsor example above. The config file that you just saw shows how to add these types to the Unity container.

So how do we go about using one of these types from the Unity container, well that's fairly simple, we just do something like this:

namespace Unity
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            UnityContainer container = new UnityContainer();

            UnityConfigurationSection section = (UnityConfigurationSection)
                           ConfigurationManager.GetSection("unity");
            section.Containers.Default.Configure(container);

            // use the Current Message Formatter (see the App.Config)
            var currentIMessageFormatter =
                (IMessageFormatter)container.Resolve(
                    typeof(IMessageFormatter), "CurrentFormatter");


            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1(currentIMessageFormatter));
        }
    }
}

It can be seen from this example that we are firstly configuring the Unity container and then we are obtaining all the types we need from the container and then constructing a new Form1 object and passing these container objects to the constructor of the Form1 object.

Lets have a look at the Form1 code.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.Unity;


namespace Unity
{
    public partial class Form1 : Form
    {
        private IMessageFormatter msgFormatter;
        private int currentMessageCount = 0;

        public Form1()
        {
            InitializeComponent();
        }

        public Form1(IMessageFormatter msgFormatter)
            : this()
        {
            this.msgFormatter = msgFormatter;
        }

        private void btnGo_Click(object sender, EventArgs e)
        {
            lstItems.Items.Add(msgFormatter.FormatMessage(
                String.Format("CurrentMessage {0}",
                currentMessageCount++)));
        }

		.....
		.....
    }
}

From here we can see that the types that the Form1 object needs for its constructor have been resolved by the Unity container and supplied to the Form1 constructor. Cool.

So what happens when we run the app. Well much the same as the Castle Windsor example, we get a message formatted using the current (App.Config type that is use) IMessageFormatter interface implementation.

Unity Container : Generics Support

So that's cool, we now have DI working with constructor parameters using the Unity container. So what else can we do, surely there is more. Well yeah there is actually. Much the same as Castle Windsor allowed us to work with generics so to does Unity allow us to work with generics. Here is an example (again using the same interfaces as the Castle Windsor example) of how to do this.

Here is what you need to do for the App.Config file to support generics.

<?xml version="1.0" encoding="utf-8" ?>
<configuration>

  <!-- Custom Config Sections -->
  <configSections>
    <section name="unity"
        type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
              Microsoft.Practices.Unity.Configuration" />
  </configSections>

  <!-- Unity Config Section -->
  <unity>
    <containers>
      <container>
        <types>
          

          <type name="DummyObjectFormatter"
              type="Unity.IGenericFormatter`1[[Unity.DummyObject,Unity]], Unity"                
              mapTo="Unity.DummyObjectFormatter,Unity"/>

        </types>
      </container>
    </containers>
  </unity>

</configuration>

In this case I am using a type of Unity.DummyObject to be the type that is used for the IGenericFormatter<T> implementaion, which if you remember was defined like this.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Unity
{
    public class DummyObjectFormatter : 
        IGenericFormatter<DummyObject>
    {

        public string FormatMessage(DummyObject valueIn)
        {
            return String.Format("The value was {0}", 
                valueIn.ToString());
        }

    }
}

So we can see that the DummyObjectFormatter is expecting to be passed a DummyObject from the Unity container. The config file section I just showed you does just that.

So how do we resolve this using the Unity container, well we simply do the following:

// use the IGenericFormatter Message Formatter
var dummyObjectFormatter =
    (IGenericFormatter<DummyObject>)
        container.Resolve(typeof(IGenericFormatter<DummyObject>),
        "DummyObjectFormatter");

And if we examine the constructor of a Form1 object that requires such a type to be provided, it should be pretty obvious that all we need to do is pass the container obtained generic object to the Form1 objects constructor.

public Form1(IMessageFormatter msgFormatter,
    IGenericFormatter actualGenTest)
    : this()
{
    this.msgFormatter = msgFormatter;
    this.actualGenTest = actualGenTest;
}

Unity Container : Property Support

I was a little luckier when working with Unity than I was with Castle and managed to get it to work by injecting property values as well as constructor values. I am positive Castle Windsor does this also, I think I just missed a trick somewhere.

Anyway what you need to do in Unity to get a DI property to work is simply mark the property up with a special Unity attribute, which is shown below.

Here is a simple program file to launch a simple form which has a single property that requires a type to be supplied by the Unity container.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using Microsoft.Practices.Unity;
using Microsoft.Practices.Unity.Configuration;
using System.Configuration;

namespace UnityPropResolution
{
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            UnityContainer container = new UnityContainer();
            UnityConfigurationSection section = (UnityConfigurationSection)
                           ConfigurationManager.GetSection("unity");
            section.Containers.Default.Configure(container);

            Application.Run(container.Resolve<Form1>());
        }
    }
}

And here is the very simple form, take special note of the Unity [Dependency] attribute usage:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using Microsoft.Practices.Unity;

namespace UnityPropResolution
{
    public partial class Form1 : Form
    {

        private IMessageFormatter currentFormatter;
        private int currentMessageCount = 0;


        [Dependency("CurrentMessageFormatter")]
        public IMessageFormatter CurrentFormatter
        {
            get { return currentFormatter; }
            set { currentFormatter = value; }
        }

        public Form1()
        {
            InitializeComponent();
        }

        private void btnDoIt_Click(object sender, EventArgs e)
        {
            MessageBox.Show(CurrentFormatter.FormatMessage(
                String.Format("CurrentMessage {0}",
                currentMessageCount++)));
        }
    }
}

If we examine what this looks like when running, we can see the CurrentFormatter got resolved just fine, by the Unity container.

 

Quick Round Up

I quite like both Unity and Castle Windsor, I spent a bit of time examining other frameworks such as those listed below, but I leant towards the 2 I talked about here. In my humble opinion both Unit and Castle Windosr are excellent products that fill the IOC/DI gap nicely, so if you find you would like to try these out, I would recommend either of these.

 

Other Frameworks Worth A Mention

  • Spring .NET : A quite mature (but I found quite tricky to use) framework covering all sorts of cool stuff, such as : AOP/Persistence/IOC/DI amongst other things
  • Pico .NET : A stand alone IOC Container
  • Lin Fu : This is a framework that offers DynamicProxy/IOC amongst other things, this is by a very very talented guy called Philip Laureano, and he has published all the source code right here at codeproject. He is very very smart, and his ideas are well worth a look.

 

That's it

That is all I have to say, I hope this article has helped you a little, if you liked it could you please be kind enough to leave a vote or a message. Thanks

 

 

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


Member
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 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

Occupation: Software Developer (Senior)
Location: United Kingdom United Kingdom

Other popular C# articles:

Article Top
You must Sign In to use this message board.
FAQ FAQ 
 
Noise Tolerance  Layout  Per page   
 Msgs 1 to 17 of 17 (Total in Forum: 17) (Refresh)FirstPrevNext
GeneralThanks again Sacha PinmemberMember 34199854:04 22 Jan '09  
GeneralRe: Thanks again Sacha PinmvpSacha Barber5:05 22 Jan '09  
GeneralRe: Thanks again Sacha PinmemberJason Down5:51 22 Jan '09  
GeneralOther Containers and the ALT.NET movement PinmemberRainer Schuster3:02 12 Jan '09  
GeneralRe: Other Containers and the ALT.NET movement PinmvpSacha Barber3:18 12 Jan '09  
GeneralRe: Other Containers and the ALT.NET movement PinmemberRainer Schuster3:22 12 Jan '09  
GeneralRe: Other Containers and the ALT.NET movement PinmvpSacha Barber3:53 12 Jan '09  
GeneralStructuremap Pinmemberchrissie122:18 5 Jan '09  
GeneralRe: Structuremap PinmvpSacha Barber22:53 5 Jan '09  
GeneralRegarding WikiPedia.and ThoughtWorks PinmemberUser of Users Group5:37 2 Jan '09  
GeneralRe: Regarding WikiPedia.and ThoughtWorks PinmvpSacha Barber5:55 2 Jan '09  
GeneralVisual Designer for XML files PinmemberDmitri Nesteruk5:35 2 Jan '09  
GeneralRe: Visual Designer for XML files PinmvpSacha Barber5:56 2 Jan '09  
GeneralRe: Visual Designer for XML files PinmemberDmitri Nesteruk5:59 2 Jan '09  
GeneralRe: Visual Designer for XML files PinmvpSacha Barber6:29 2 Jan '09  
JokeWhere is the... PinsitebuilderUwe Keim4:54 2 Jan '09  
GeneralRe: Where is the... PinmvpSacha Barber5:57 2 Jan '09  

General General    News News    Question Question    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

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

PermaLink | Privacy | Terms of Use
Last Updated: 2 Jan 2009
Editor:
Copyright 2009 by Sacha Barber
Everything else Copyright © CodeProject, 1999-2010
Web22 | Advertise on the Code Project