Click here to Skip to main content
15,880,651 members
Articles / Desktop Programming / WPF
Article

Templates, Inversion of Control, Factories, and so on

Rate me:
Please Sign up or sign in to vote.
4.75/5 (5 votes)
8 Jul 2011CPOL11 min read 22.8K   270   18   6
This article gives a little presentation of Control Templates, Data Templates, Inversion of Control, and Factories, explaining why they are all related and how to better use them.

Introduction

Factories are used to remove direct dependency from code. Inversion of Control, Templates, plug-ins, and so many other things do the same. They may have small differences and implementations, but the very essence is the same. You have some kind of data, even if it is only the DataType of a record, and the appropriate editor/visualizer will be created/shown by some framework.

In WPF, the DataTemplates can be attached later to show some kind of data. So I can put 100 instances of MyData without creating a control to show them, and a designer may create the appropriate look for them. I will not change my class and I will not add instances of MyDataVisualizer to put into the ListBox, but WPF will create the right objects to put into the screen at some moment.

The difference between them

In my opinion, Inversion of Control is the most generic term for the concept. If I understand well, Inversion of Control means that it is a framework that's responsible for creating the appropriate control, not the programmer. If you only need to call something like SomeClass.Show(value) and the value is correctly shown in the application you are working on, even if you don't know if it is running on the web, on the Desktop, Silverlight, WPF, Windows Forms, or anything else, there is already an Inversion of Control.

A Factory is, in fact, one of the most common implementations, but it is still too generic. For me, a Factory capable of loading external plug-ins and one that only knows already loaded classes are both Factories, even if the first one is more capable than the other. If your class does its work by a giant switch, it surely lacks Dependency Injection, as such classed will need all the references when compiled, but it is still Inversion of Control. The user of such a class doesn't need to know how it is working. But, a common Factory usually works like a dictionary, so the Factory class doesn't know all the possible implementations when it is compiled, but at runtime, it may load all the implementations needed/available.

In WPF, DataTemplates and ControlTemplates are already Inversion of Control and the templates may be added at any moment, so the WPF framework already allows Dependency Injection and it is, in fact, implemented as a Factory.

The limitations

I always used Factories to create dynamic forms. If I think that I can add three objects of different types into a ListBox and WPF will try to find a template to show them, then WPF is already giving me the dynamic form I always wanted.

But that's not enough for me. In general, data templates are to show read-only data. To edit things, we must use Controls and, even if ControlTemplates exist, that creates a strong dependency to those controls.

Surely I know I must put a TextBox to edit a text value and a ComboBox to edit a boolean value, but what if I want to discover that at runtime? For example, I want to create the simplest form to edit all the properties of an object. With such an object, I can discover all their properties and property types, but the System.String type doesn't tell me that I must use a TextBox nor does the System.Boolean type tell me that I should use a CheckBox.

The Solution

Create a new Factory. The simplest Factory can look like this:

C#
public static class SimplestControlFactory
{
    private Dictionary<Type, Func<Control>> _dictionary = 
            new Dictionary<Type, Func<Control>>();

    public void Register(Type type, Func<Control> func)
    {
        if (type == null)
            throw new ArgumentNullException("type")

        if (func == null)
            throw new ArgumentNullException("func");

        lock(_dictionary)
            _dictionary[type] = func;
    }
    public Control Create(Type dataType)
    {
        if (dataType == null)
            throw new ArgumentNullException("dataType");

        Func<Control> func;
        lock(_dictionary)
            func = _dictionary[dataType];

        return func();
    }
}

With it, we can register a function that creates a control (and even configures it) for each DataType, and then we can ask the Factory to create a control for each of those registered DataTypes.

It surely lacks better exception handling, as it will simply throw a dictionary exception if the DataType is not registered, but that's not the worst. I can create the right control for String, the right control for Boolean... but how do I get the value on those controls?

If the controls are created only to edit properties, I may want to pass a property during the control creation so I can build a bind. If I really want to create an unbound control, I may want to create a new class (like ValueControlBase) which has a Value property, and then all of my controls will need to inherit from it, creating the right TextBox and redirecting the Value to Text, or creating a CheckBox and redirecting the Value to IsChecked.

With only some changes to my simplest Factory, that will be possible, but I really don't want to give an implementation to this one. In my opinion, the problem is not having to create a new sub-class of ValueControlBase for each supported type, it is the fact that I can't simply create one for typeof(Enum) and make it work for any enum I may create. I will need to register one for each enum type I may use, even if they will all redirect to the same combobox that lists all the possible values. Adding some events in which I can check for enum may help, and it will be a good solution already. But I already have a more complete one, so I will use that one, which I will explain later.

What a simple Control Factory already allows us to do

If I simply want to create a single form to edit an object passed to it, I can use Reflection to list all properties (or fields, depending on the preference) and create the appropriate control by the property type. Then I can get the property value and put into the control and, at some moment, do the opposite.

Even if each ValueControlBase's inheritor must be registered, the SimplestControlFactory may be in a separate library, used by many projects, and will be able to create the appropriate control to any project, as long as the appropriate controls are registered before needed (probably during load time).

This solves the problem of editing unknown typed values. Using a StackPanel, we will simply put a value per row. It may not be the most appealing form, but will allow to edit any object. So, as long as there is no reason to create the most appealing editor, we are done.

Edits and searches

I just said "as long as there is no reason to create the most appealing editor, we are done". But what if we have a reason to create a better looking editor? Today I may use the generic editor for everything, but tomorrow, I may want to use a different editor to edit Persons. Putting a direct dependency to the PersonEditor control/window can be problematic, specially if we already have generic lookups using the generic editor. So, how do we solve it? Another Factory. Now we need a Factory for Editors. I will go further and say, we need a Factory for Searches too (and in the future, we may want a Factory for Reports and so on). So, to avoid creating many Factory classes that will look very similar, I decided to create the Factories generic class. I can use Factories<IEditor> to have access to the Factories for Editors, Factories<ISearcher> to have access to the Factories for Searches... and, of course, Factories<IValueControl> to have access to the Factories for ValueControls, those controls that edit each value. As long as we create a new interface that serves as the base to our Factories, we are done.

The factory is also capable of registering editors, searches, or so on to work for sub data-types. So our generic object editor may be registered to System.Object and all its sub-types. The factory is capable of first looking for the most specific editors and then looking for the most generic ones (if there are any).

What we can do now

Now our lookups may search for records creating the appropriate Searcher, or may create new records using the appropriate Editor. Our most basic editor simply gets all the properties and shows them in a StackPanel, using the registered ValueControls. But that's accessible by code only.

Also, to make everything more reusable, I prefer to work with Controls instead of Windows, so I can put a search inside another Window if I want. The problem is that we don't have easy ways of showing them at this moment.

ValueControl, PropertyBoundControl, EditorControl, and SearcherControl

To solve this problem, I created the ValueControl and the PropertyBoundControl. In fact, a ValueControl is a control with a DataType and a Value property. As expected, it will use the Factory to create the appropriate IValueControl instance, but makes it easier to create your window layout, as you can put the ValueControl where you want at design time.

The PropertyBoundControl uses the value control internally, but then binds its value to the property of some object. Its real advantage at this moment is that it allows you to create the layout to edit any property at design time, but only depending on the real type or the property at run-time.

EditorControl and SearcherControl are like the ValueControl, but one focused for Editors while the other for Searchers.

Helper classes

The generic type Factories is very good at making all possible factories accessible at a single place but, as it happens to many generic code, it lacks some easier to use methods. As the class is static, not even Extension Methods could be used, so I created the Editor and the Searcher classes.

With EditorControl and SearcherControl, you can already put an editor or a searcher into another window, but if you want to simply edit the actual record and don't know where the editor will be shown, then you will prefer to use the Editor class.

The Editor and Searcher classes by default create a Modal window to show the appropriate editor or searcher. Such behavior can be replaced by filling the Searching or Editing properties. It may look wrong, but they are properties, instead of events, because registering one must unregister the old one.

Going further on Dependency Injection (or independent code)

Dependency Injection means that dependencies are discovered at run-time. There is no real dependency on the objects at design time or even compile time.

But have you been in this situation before:

At some event, you call Screen X. Clicking on OK or Cancel Screen X must either return synchronously (ShowModal/Dialog, for example) or must know that it must return to some page (web posts, in general). Even when returning synchronously, modal windows return true/false or ModalResult. If you are in a search, you will need to get the results by another property. Well, to try to solve those problems, I consider that at any point, you must set a result by calling a common method... so I decided to put such a method in the ResultSetter class. When you call ResultSetter.SetResult, it will call a registered Action for the actual thread to know how the result will be processed. But as a delegate, it must be set first. In Web-Logic, the Page creation must set the actual delegate to post to another page. In Windows Forms, it must set the result to the actual window and then set its ModalResult. That way, many classes may work as a workflow, knowing when to Edit a record, when to Search for something, but won't have a clue on how that will really happen.

The sample

The sample is a small database application that uses SQL Server CE 4.0 as its repository (download here: http://www.microsoft.com/download/en/details.aspx?id=17876). It does not have an appealing visual, but its real purpose is to show how useful Factories are to build database systems.

In the application, I created a Searcher for any record that is an INamedRecord, a Searcher for the classes, and an Editor for the classes that allows to add many students into a single class. To Edit the students info, the teachers info, and the available courses, you will need to use the lookup controls available in the class editor. I could've made buttons in the main window to edit or search students directly, but my purpose was to show how lookups are working all the time thanks to the Editors and Searchers, while the lookups are themselves ValueControls.

This sample does not delete records and it uses my own personal framework to access the database. That's not mandatory for the Factories, but I really prefer to use my own database framework.

Also, this sample creates the database in the actual directory by default. You can change the directory by the application config. If you change the database classes, you must update (or more easily delete) the database created and the new fields (properties in the database interfaces) will be shown in the screen when editing the records. If you create new types, you will probably need to register new editors (see in the Editors folder for a sample) and a new Database Type Converter (see in Database/Converters for a sample).

License

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


Written By
Software Developer (Senior) Microsoft
United States United States
I started to program computers when I was 11 years old, as a hobbyist, programming in AMOS Basic and Blitz Basic for Amiga.
At 12 I had my first try with assembler, but it was too difficult at the time. Then, in the same year, I learned C and, after learning C, I was finally able to learn assembler (for Motorola 680x0).
Not sure, but probably between 12 and 13, I started to learn C++. I always programmed "in an object oriented way", but using function pointers instead of virtual methods.

At 15 I started to learn Pascal at school and to use Delphi. At 16 I started my first internship (using Delphi). At 18 I started to work professionally using C++ and since then I've developed my programming skills as a professional developer in C++ and C#, generally creating libraries that help other developers do their work easier, faster and with less errors.

Want more info or simply want to contact me?
Take a look at: http://paulozemek.azurewebsites.net/
Or e-mail me at: paulozemek@outlook.com

Codeproject MVP 2012, 2015 & 2016
Microsoft MVP 2013-2014 (in October 2014 I started working at Microsoft, so I can't be a Microsoft MVP anymore).

Comments and Discussions

 
SuggestionMy vote of 2 Pin
tilutza8-Dec-14 1:20
tilutza8-Dec-14 1:20 
GeneralRe: My vote of 2 Pin
Paulo Zemek8-Dec-14 7:24
mvaPaulo Zemek8-Dec-14 7:24 
GeneralMy vote of 5 Pin
KentuckyEnglishman12-Jul-11 3:51
KentuckyEnglishman12-Jul-11 3:51 
GeneralRe: My vote of 5 Pin
Paulo Zemek12-Jul-11 4:28
mvaPaulo Zemek12-Jul-11 4:28 
GeneralMy vote of 4 Pin
MicroImaging9-Jul-11 9:39
MicroImaging9-Jul-11 9:39 
GeneralRe: My vote of 4 Pin
Paulo Zemek9-Jul-11 10:33
mvaPaulo Zemek9-Jul-11 10:33 

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

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