background image

8,6 31,239 me mb e rs and  g ro wing !

E

m

a

i

l

 

 P

a

s

s

w

o

r

d

 

 

Sig n in

 

 

Jo in

  

 

L

o

s

t

 

p

a

s

s

w

o

r

d

?

Ho m e

Art icle s

Quick Answe rs

Discussio ns

Le arning Z o ne s

Fe at ure s

He lp!

The Lo unge

Search site

Art icle

Bro wse  Co de St at s Re visio ns Alt e rnat ive s

 

 » 

Development Lifecycle

 » 

Design and Architecture

 » 

Frameworks

 

6

 

Licence 

CPOL

First Posted  11 Fe b  2008
Views 

4 8,133

Downloads  515
Bookmarked 79 t ime s

B

u

i

l

d

i

n

g

 

a

n

 

M

V

P

 

F

r

a

m

e

w

o

r

k

 

f

o

r

 

.

N

E

T

.

 

P

a

r

t

 

2

:

I

m

p

l

e

m

e

n

t

i

n

g

 

C

o

r

e

 

F

u

n

c

t

i

o

n

a

l

i

t

y

By 

Oleg Zhukov

 | 11 Feb 2008

C# .NET Dev Intermediate

Basing on the concepts introduced in the first part, this article proceeds to implement the core MVP Framework funtionality.

 

 

See Also

More like this
More by this author

   4.81 (19 votes)

Download source -  167.65 KB

Table of Contents

Introduction
Basic Requirements
Designing Key Classes
Designing a Simple Views Manager
Summary

Introduction

In the 

previous article

, we have made our choice in favour of the Model- View- Presenter architectural pattern. Thus our final goal

is the creation of the MVP Framework. However we should firstly make it clear what does “MVP Framework” mean by deciding
what the future system will be intended for and what problems it will solve.

In this article, we will start with clarifying the aim of our system and gathering some basic requirements for it. After that we will
proceed to the design and implementation stages creating fundamental classes that will meet our basic requirements.

Basic Requirements

Hot News: 

10 Best Practices of Code

Commenting & Formatting

The Code Project Insider. 

Free each

morning.

 

PDFmyURL.com

background image

The aim of our system can be formulated as follows: it should simplify the usage of the MVP pattern by developers. The system
should make it easier to fulfill every common task within the MVP approach. For example it should simplify such actions as
navigating between views, accessing controllers, etc. For each common operation, we will analyz e how our system can help in
performing it and by doing so we will construct requirements to the system. We will express the requirements in a popular form
of use cases, each describing the desired interactions between a user and the system.

Starting a Task

To begin with, let us consider how a user would start a task. Starting a task implies certain processing (registering and
initializ ing the task) so it would be nice to delegate this work to the system (MVP Framework). A user should be able to specify
actions performed on a task started by implementing some 

OnStart 

method. Thus given a task descriptor the system should

perform necessary processing and call the task 

OnStart 

handler.

 Collapse | Copy Code

Starting a task
    User: Pass the task descriptor to the system and ask to start the task.
    System: Register the task, initialize it and invoke OnStart handler.

Here a task descriptor is something that describes the task, specifically its structure and its properties. Let us decide what will
be convenient to use as a task descriptor.

Since every task is a part of an application we might want to describe tasks directly in the source code of the application. A
good way of defining an entity (such as task) in source code is using a type definition construct. Therefore a task type can be
used as its descriptor. Moreover a task type (class) may define 

OnStart 

handler method and an instance of this type can

hold the task state at runtime. So this is how the revised version of the “Starting a task” use case looks:

 Collapse | Copy Code

Starting a task (revision 1)
    User: Pass the task type to the system and ask to start the task.
    System: Create a task instance, register and initialize it and invoke its
            OnStart operation.

Of course there must be some Framework class which processes start task requests from a user. Let us call it

TasksManager

:

Navigating From Within a Task

Related Articles

Building an MVP Framework for .NET.
Part 1: The Basics of MVC and MVP
Building an MVP Framework for .NET.
Part 4: Strongly Typed Associations
Building an MVP Framework for .NET.
Part 3: Designing a Windows Forms
Views Engine
Advanced Unit Testing, Part II -  Core
Implementation
Implementing Audit Trail using Entity
Framework Part - 1
Entity Framework Implementation
Using ASP.NET MVP
Building Applications with the
SharpDevelop Core
Implementing Audit Trail using Entity
Framework -  Part 2
The Raz or Framework :: Part 1 ::
Plugins/Extensibility
MVP Dependency Chaining
Framework

 

PDFmyURL.com

background image

Navigating From Within a Task

Every task involves a number of views with transitions possible between them. At this point, let us discuss how a user would
navigate to some view from a task code. Say some view should be activated in the 

OnStart 

handler code. It would be

convenient if the navigation is done by the Framework and the navigation logic is isolated in some 

Navigator 

class. Then

each user task instance should be associated with a proper navigator instance.

 Collapse | Copy Code

Navigating from within a task
    Precondition: The task is associated with a proper navigator instance.
    User: Ask that associated navigator to navigate to some view.
    System: Do the navigation, alter the task state.

It is important to note that the precondition requires each task to be linked to its navigator. Such linking may be done during the
task start process. So here is the modified version of “Starting a task” use case:

 Collapse | Copy Code

Starting a task (revision 2)
    User: Pass the task type to the system and ask to start the task.
    System: Create a task and a navigator instances, initialize and link them
            together. Invoke the OnStart operation on the task instance.

Using Various Presentation Mechanisms

According to the MVP paradigm the system should make it easy to use different presentation mechanisms for example Web or
Windows UI. A presentation mechanism has influence upon how switching between views is done. Therefore it seems quite
reasonable to encapsulate view- switching code in a separate 

ViewsManager abstract 

class with subclasses for each

specific UI kind. Then the 

Navigator 

class containing some common navigation logic will be associated with the

ViewsManager 

class.

We cannot yet formulate any use case for this requirement however the arguments above proves the need of the

ViewsManager 

concept. Thus the domain model at the moment looks as follows:

A framework for building of WP7
application
Dependency Injection Frameworks -
Part 1 -  Introduction
Implement Script Callback Framework
in ASP.NET 1.x
Driver Development Part 2:
Introduction to Implementing IOCTLs
The Raz or Framework :: Part 2 ::
Configuration/Options
Implementing the Factory Pattern
(Part 1 of 2 or 3)
Managed Extensibility Framework:
Part 2
Cinch V2: Version 2 of my Cinch
MVVM framework: Part 1 of n
Genesis Hybrid Smart Client
Framework -  Part I
Genesis Hybrid Smart Client
Framework part II

 

PDFmyURL.com

background image

Describing a Task Structure

From the previous article we know that every task consists of a number of interaction points. Each interaction point in its turn is
characteriz ed by its view, controller and possible transitions to the other interaction points (in the previous article we decided to
use "Controller" notation instead of "Presenter" so do not get confused with such naming). A picture illustrating this is below:

For each linked pair of source and target interaction points, the 

NavigationTrigger 

instance defines a trigger which

should be called to perform the navigation. For example a trigger “Next” may cause a transition from “Step1” view to “Step2”
view in a wiz ard- like application.

Notice that we don't specify any view type in the 

InteractionPointInfo 

class since specific view implementations are

the prerogative of view managers.

As we have decided to describe a task by its type, let us find out how we can accompany a type definition in .NET with a task

 

PDFmyURL.com

background image

As we have decided to describe a task by its type, let us find out how we can accompany a type definition in .NET with a task
structural information. Interaction points can be declared in a form of constant fields inside the task type. This allows referencing
interaction points in a compiler- checked way rather than using literal strings. For example one may call

Navigate(MyTask.View1) 

instead of 

Navigate("View 1")

.

 Collapse | Copy Code

class

 WashDishesTask

{
    

// Below are three interaction point definitions

    

// with the view names specified

    

public

 

const

 

string

 SelectDishes = 

"Select dishes view"

;

    

public

 

const

 

string

 Dishwasher = 

"Dishwasher view"

;

    

public

 

const

 

string

 WashComplete = 

"Wash complete view"

;

}

Such constant field alone describes an interaction point party, specifying only the view name. We need a means to accompany
such fields with controller type and navigation triggers declarations. A good way to equip language elements (fields, in
particular) in .NET with some additional info is using .NET custom attributes. In our case it might look as follows:

 Collapse | Copy Code

class

 WashDishesTask

{
    [InteractionPoint(

typeof

(SelectDishesController))]

    [NavTarget(

"Next"

, Dishwasher)]

    

public

 

const

 

string

 SelectDishes = 

"Select dishes view"

;

    [InteractionPoint(

typeof

(DishwasherController))]

    [NavTarget(

"Next"

, WashComplete)]

    [NavTarget(

"Previous"

, SelectDishes)]

    

public

 

const

 

string

 Dishwasher = 

"Dishwasher view"

;

    [InteractionPoint(

typeof

(WashCompleteController))]

    

public

 

const

 

string

 WashComplete = 

"Wash complete view"

;

}

The suggested approach here for describing tasks seems to be more or less handy to start with. With it the revised version of
the "Starting a task" use case looks so:

 Collapse | Copy Code

Starting a task (revision 3)
    User: Add fields describing interaction points to the task type. Equip these
          fields with [InteractionPoint] and [NavTarget] attributes. Then pass
          the task type to the system and ask to start the task.
    System: Extract the task information from its type. Create a task and a
            navigator instances, initialize and link them together. Invoke the
            OnStart operation on the task instance.

 

PDFmyURL.com

background image

Accessing the Controller From a View and Vice Versa

According to the MVP pattern views handle user gestures and then pass control to the corresponding controller (and again I
recall that we are using the "controller" name instead of "presenter"). Moreover in MVP (in contrast to MVC) controllers may
access their views as well. Hence it should be easy for a user to access the controller from a view code and vice versa. In
MVP this is solved by linking together each view with the corresponding controller instance.

 Collapse | Copy Code

Accessing the controller from a view and vice versa
    Precondition: View and its controller are linked to each other.
    User: Access that associated controller/view. 

For user’s convenience it should be the Framework job to link views and controllers together. Later when designing classes we
will discuss which class will be responsible for such linking.

Accessing the Task and Navigating From a Controller

Controllers often need to request/modify their task state. So we may require each controller to be linked to its task.

 Collapse | Copy Code

Accessing the task from a controller
    Precondition: Controller is linked to its task.
    User: Access that associated task.

A controller may also need to trigger navigation to some view. This is done easily by accessing the task and then getting its
navigator.

 

PDFmyURL.com

background image

 Collapse | Copy Code

Navigating from within a controller
    Precondition: Controller is linked to its task which is connected to the
                  navigator
    User: Access the navigator through the associated task. Invoke the navigation.

We have discussed the most fundamental requirements for the future system. Based on these requirements, we are going to
proceed to designing classes.

Designing Key Classes

Above we have introduced a number of fundamental concepts such as task, navigator and others by analyz ing requirements
for our system. These concepts with the relationships between them make up so called analysis model of the system. Analysis
classes from this model usually turn into design classes by being equipped with operations, additional attributes and other
details.

Here we are going to walk through all the requirements we have formulated and design classes based on the analysis model in
order to meet these requirements.

TasksManager

First let us deal with the “Starting a task (revision 3)” use case and the 

TasksManager

 concept. According to this use case

we may introduce a 

TasksManager

 class with a 

StartTask(taskType: Type)

 method. This method should create

task and navigator instances, connect them to each other and invoke the task’s 

OnStart() 

method. It should also create a

TaskInfo 

instance based on the task type. Tasks are designed by users however in order for the Framework to

communicate with task instances the latter should conform to some interface. Let us call it 

ITask

. There is also a requirement

we have missed: tasks should be able to access their tasks manager, that is why the 

TasksManager 

should also link the

created task to itself.

 Collapse | Copy Code

public

 

class

 TasksManager

{
    

public

 ITask StartTask(Type taskType)

    {
        TaskInfo ti = GetTaskInfo(taskType); 

// get TaskInfo from task type

        Navigator n = 

new

 Navigator(); 

// create navigator

        ITask t = CreateHelper.Create(taskType) 

as

 ITask; 

// create task

        t.TasksManager = 

this

// link the created task to itself

        n.Task = t; 

// connect the navigator to the task

        t.Navigator = n; 

// and the task to the navigator

        t.OnStart(); 

// invoke the task's OnStart()

        

return

 t;

    }
}

 

PDFmyURL.com

background image

GetTaskInfo 

is a method that extracts task information from a task type. Above we suggested to describe tasks by inserting

constant fields to the type definition. However there may be other ways to equip a task type with the task information. Hence
different methods to extract such information may exist. We will isolate the extraction logic in a 

ITaskInfoProvider

interface with a 

GetTaskInfo(taskType: Type): TaskInfo

 method.

 Collapse | Copy Code

public

 

interface

 ITaskInfoProvider

{
    TaskInfo GetTaskInfo(Type taskType);
}

It is worth keeping all configuration data including task and view descriptions in a centraliz ed 

MVCConfiguration 

class.

Then each tasks manager will be linked to its own 

MVCConfiguration 

instance:

 Collapse | Copy Code

public

 

class

 TasksManager

    ...
    

public

 MVCConfiguration Config

public

 

class

 MVCConfiguration

    ...
    

public

 ITaskInfoProvider TaskInfoProvider

A user may start a task of the same type more then once; and extracting the task information each time is redundant. That is
why we need a repository object for all tasks configuration data. Let it be 

TaskInfoCollection 

instance.

 Collapse | Copy Code

public

 

class

 MVCConfiguration

    ...
    

public

 TaskInfoCollection TaskInfos

If the necessary task info object already exists in the inner hash table the 

TaskInfoCollection 

will return it, otherwise it

will extract a new 

TaskInfo 

object from the task type with the help of the 

TaskInfoProvider 

class:

 Collapse | Copy Code

public

 

class

 TaskInfoCollection

{
    

private

 Hashtable taskInfos = 

new

 Hashtable();

    

private

 MVCConfiguration mvcConfig;

    

public

 TaskInfo 

this

[Type taskType]

    {
        

get

        {
            TaskInfo ti = taskInfos[taskType] 

as

 TaskInfo;

            

if

 (ti == 

null

)

 

PDFmyURL.com

background image

            

if

 (ti == 

null

)

            {
                ti = mvcConfig.TaskInfoProvider.GetTaskInfo(taskType);
                taskInfos[taskType] = ti;
            }
            

return

 ti;

        }
        

set

 { taskInfos[taskType] = value; }

    }
}

Finally this is how the 

TasksManager.GetTaskInfo(...) 

method looks:

 Collapse | Copy Code

public

 

class

 TasksManager

    ...
    

private

 TaskInfo GetTaskInfo(Type taskType)

    {
        

return

 Config.TaskInfos[taskType];

    }

Navigator

Now let us look into how the navigation occurs. 

Navigator

 class should have a 

public Navigate(..) 

method with a

navigation trigger name passed as parameter.

For a navigator to switch to another view it needs to know the task navigation structure. Therefore it should be linked to the

TaskInfo 

instance describing that task. Such linking can be done in the 

TasksManager.StartTask(...) 

method:

 Collapse | Copy Code

public

 

class

 TasksManager

...
    

public

 ITask StartTask(Type taskType)

    {
        ...
        n.TaskInfo = ti;
        ...
    }

Task information is not the only needed component for a navigator to do the navigation. Another important thing we have
introduced in the analysis phase is the views manager concept. Its responsibility is actual view switching, with different views
manager implementations capable of different presentation mechanisms. The navigator will be connected to the views
manager in the 

TasksManager.StartTask(...) 

method:

 Collapse | Copy Code

public

 

class

 TasksManager

    ...

 

PDFmyURL.com

background image

    

public

 ITask StartTask(Type taskType)

    {
        ...
        IViewsManager vm = CreateHelper.Create(Config.ViewsManagerType)
                           

as

 IViewsManager;

        n.ViewsManager = vm;
        vm.Navigator = n;
        ...
    }

Note that we are using the 

MVCConfiguration 

class to store the used views manager type.

Now we are ready to write code for the 

Navigator.Navigate(...) 

operation:

 Collapse | Copy Code

public

 

class

 Navigator

{
    ...
    

public

 TaskInfo TaskInfo

    ...
    

public

 IViewsManager ViewsManager

    ...
    

public

 

void

 Navigate(

string

 triggerName)

    {
        

string

 nextViewName = TaskInfo.GetNextViewName(Task.CurrViewName,

                                                       triggerName);
        

if

 (nextViewName == Task.CurrViewName) 

return

;

        NavigateDirectly(nextViewName);
    }

    

public

 

void

 NavigateDirectly(

string

 viewName)

    {
        Task.CurrViewName = viewName;
        ViewsManager.ActivateView(Task.CurrViewName);
    }
}

Designing a Simple Views Manager

Up to the moment, we have roughly designed all key classes except for a views manager class. Let us build a simple

IViewsManager 

implementation. Although simple, it will be a basis for more complicated real- life views managers.

To make our views manager as simple as possible let us assume that views are usual Windows Forms. Then our

SimpleFormsViewsManager 

will be responsible for switching between those Forms.

 

PDFmyURL.com

background image

ViewInf o

In order to activate a form for the first time it needs to be created. Therefore the views manager should know the view type by
its name. We will encapsulate the information about a view type in a 

ViewInfo 

class instance. Thus, given a view name, the

view manager should retrieve the corresponding 

ViewInfo 

object through the intermediate 

ViewInfoCollection

object.

 Collapse | Copy Code

public

 

class

 ViewInfoCollection

    ...
    

public

 ViewInfo 

this

[

string

 viewName]

    {
        

get

 { 

return

 viewInfoCollection[viewName] 

as

 ViewInfo; }

        

set

 { viewInfoCollection[viewName] = value; }

    }

    

public

 

class

 ViewInfo

    ...
    

public

 Type ViewType

Subsequent (second, third, etc.) view activations don't require the view creation. Instead they require locating the already
created view by its name. For this, the views manager should have an association to a 

FormCollection 

class returning

already created views by their names.

 Collapse | Copy Code

public

 

class

 SimpleFormsViewsManager : IViewsManager

 

PDFmyURL.com

background image

public

 

class

 SimpleFormsViewsManager : IViewsManager

    ...
    

private

 Dictionary<

string

, Form> forms

            = 

new

 Dictionary<

string

, Form>();

The question is where a views manager takes the view descriptions (

ViewInfo 

objects) from. As views are parts of a task it

is natural to store their descriptions within that task’s description:

 Collapse | Copy Code

public

 

class

 TaskInfo

    ...
    

public

 ViewInfoCollection ViewInfos

This approach does not bind tasks to any specific presentation mechanism since the base 

ViewInfo 

class is independent

of a specific presentation.

Next question is how a 

ViewInfoCollection 

gets populated. Obviously a user can modify the collection at runtime.

However usually a task structure is known at design time, and a declarative syntax to describe it may apply. A good solution is
to mark view types with a 

[View] 

attribute like this:

 Collapse | Copy Code

[View(

typeof

(Task1), “View1”)]

class

 Form1: Form

Here we declare that the 

TaskInfo 

object for 

Task1 

should contain a 

ViewInfo 

instance pointing to the 

Form1 

type.

Of course there should be a class which will generate 

ViewInfo 

objects from such declarations. Let us assign this

responsibility to a 

IViewInfosProvider 

interface with a 

GetFromAssembly(assembly:Assembly)

 operation. It

will generate 

ViewInfo 

objects from the declarations in the input assembly:

 Collapse | Copy Code

public

 

interface

 IViewInfosProvider

{
    ViewInfosByTaskCollection GetFromAssembly(Assembly assembly);
}

public

 

class

 DefaultViewInfosProvider : IViewInfosProvider

...

ActivateView Implementation

In general the view activation mechanism is quite simple: the necessary form should be found by its name and then the

Form.Show() 

and 

Form.Activate() 

methods should be called on it.

 Collapse | Copy Code

public

 

class

 SimpleFormsViewsManager : IViewsManager

 

PDFmyURL.com

background image

    ...
    

public

 

void

 ActivateView(

string

 viewName)

    {
        Form f = FindOrCreateView(viewName);
        f.Show();
        f.Activate();
    }

The 

FindOrCreate 

operation above should create the view in case it does not exist yet. Of course a view creation implies

certain initializ ation steps. These steps may be derived from the requirements to our system. Take a look at the “Accessing the
controller from a view and vice versa” use case. It requires a view to be linked to the controller during the initializ ation process:

 Collapse | Copy Code

public

 

class

 SimpleFormsViewsManager : IViewsManager

    ...
    

private

 Form FindOrCreateView(

string

 viewName)

    {
        Form result;
        

if

 (!forms.TryGetValue(viewName, 

out

 result))

        {
            result = CreateHelper.Create(ViewInfos[viewName].ViewType) 

as

 Form;

            forms[viewName] = result;
            (result 

as

 IView).ViewName = viewName;

            InitializeView(result 

as

 IView);

        }
        

return

 result;

    }

    

private

 

void

 InitializeView(IView view)

    {
        view.Controller = Navigator.GetController(view.ViewName);
        view.Controller.View = view;
    }

In this code we make the 

Navigator 

class responsible for holding the controllers for its task. 

Navigator 

will also create

and initializ e controllers if needed. According to the “Accessing the task and navigating from a controller” use case, a controller
initializ ation should include its linking to the task:

 Collapse | Copy Code

public

 

class

 Navigator

    ...
    

public

 IController GetController(

string

 viewName)

    {
        IController result = controllers[viewName] 

as

 IController;

        

if

 (result == 

null

)

        {
            InteractionPointInfo iPointInf = TaskInfo.InteractionPoints[viewName];

 

PDFmyURL.com

background image

            result = CreateHelper.Create(iPointInf.ControllerType) 

as

 IController;

            result.Task = Task;
            controllers[viewName] = result;
        }
        

return

 result;

    }

Manual View Activation

What happens when a user himself clicks on a form and activates it? That means the user decides to do the navigation to the
selected view. Thus the 

Navigator.Navigate(…) 

operation should be called in response to the manual view activation.

We can implement this by handling the 

Form.Activated 

event:

 Collapse | Copy Code

public

 

class

 SimpleFormsViewsManager : IViewsManager

    ...
    

void

 view_Activated(

object

 sender, EventArgs e)

    {
        Navigator.TryNavigateToView((sender 

as

 IView).ViewName);

    }

public

 

class

 Navigator

    ...
    

public

 

void

 TryNavigateToView(

string

 viewName)

    {
        

if

 (TaskInfo.CanNavigateToView(Task.CurrViewName, viewName))

            Task.CurrViewName = viewName;
        ViewsManager.ActivateView(Task.CurrViewName);
    }

Navigator.TryNavigateToView(...)

 does the following: if navigation to the destination view is possible via any of

the navigation tree ribs (i.e. 

CanNavigateToView

 returns 

true

) then the destination view gets activated, otherwise the

source view is activated. Thus if a user clicks on a view that is not accessible from the current one, then the task will remain in
the current view and the views manager will switch back to the current view.

Summary

Throughout this article we have developed the core classes of the future MVP Framework. These classes help users in fulfilling
the main Model- View- Presenter usage scenarios, and establish a firm ground for the further Framework's growth and extension.

Note that the 

SimpleFormsViewsManager

 class sources as well as examples on using MVC# Framework are bundled

with MVC# sources and located in the Examples folder.

Proceed to Part 3: Designing a Windows Forms Views Engine

 

PDFmyURL.com

background image

Article Top

Sign Up

 to vote   Poor

Excellent

Vo t e

Se arch t his f o rum 

 

G o

Project Website

www.MVCSharp.org

License

This article, along with any associated source code and files, is licensed under 

The Code Project Open License (CPOL)

About the Author

Oleg Zhukov

Architect

 Russian Federation

Member

Oleg Zhukov, born and living in Russia is a software development consultant in a company which
provides business solutions. He has graduated from Moscow Institute of Physics and Technology
(MIPT) (department of system programming) and has got a M.S. degree in applied physics and
mathematics. His research and development work concerns architectural patterns, domain- driven
development and systems analysis. Being the adherent of agile methods he applies them
extensively in the projects managed by him.

Comments and Discussions

 

Yo u must  

Sig n In

 t o  use  t his me ssag e  b o ard . (

secure sign- in

)

 

 

Profile popups    Noise

Me d ium

  Layout

No rmal

  Per page

10

   

Up d at e

 

Refresh

First

 

Prev

 

Next

 

PDFmyURL.com

background image

P e r m a l i n k

 | 

Ad ve r ti s e  

P r i va cy

 | 

Mo b i l e

 

We b 0 1  | 2 .5 .1 2 0 4 0 5 .1  | La s t Up d a te d  11  Fe b  2 0 0 8

Ar ti cl e  Co p yr i g h t 2 0 0 8  b y O l e g  Z h u ko v

Eve r yth i n g  e l s e  Co p yr i g h t ©  

Co d e P r o j e ct

, 1 9 9 9 -2 0 1 2  

Te r m s  o f Us e

z ip Farm

3:59 5 De c ' 08  

Oleg Z hukov

18:49 5 Dec '08  

Rub e n
Chakhmakhchyan

3:4 4  27 Jun ' 08  

Oleg Z hukov

8:13 27 Jun '08  

Jo rg e  G o nz alo

23:4 4  18 Jun ' 08  

Jorge Gonz alo

23:53 18 Jun '08  

Last Visit: 19:00 31 Dec '99     Last Update: 8:27 6 Apr '12

1

 General    

 News    

 Suggestion    

 Question    

 Bug    

 Answer    

 Joke    

 Rant    

 Admin   

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

La yo u t: 

fi xe d

 | 

fl u i d

Nice ly t ho ug ht  o ut  -  b ut  co nsid e r t his...

 

Re: Nicely thought out -  but consider this...

 

wo rkf lo w mixe d  wit h MVP

 

Re: workflow mixed with MVP 

G re at  art icle ...b ut  t he  co d e  is no t  d o wnlo ad ab le !!!

 

Re: Great article...but the code is not downloadable!!!  

 

PDFmyURL.com