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

 

13

 

Licence 

CPOL

First Posted  12 Fe b  2008
Views 

4 5,734

Downloads  539
Bookmarked 71 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

 

3

:

D

e

s

i

g

n

i

n

g

 

a

 

W

i

n

d

o

w

s

 

F

o

r

m

s

 

V

i

e

w

s

 

E

n

g

i

n

e

By 

Oleg Zhukov

 | 12 Feb 2008

C# .NET Dev Intermediate

This article describes the development of the fully functional Windows Forms views engine for the MVP Framework being
constructed.

 

 

See Also

More like this
More by this author

   4.89 (16 votes)

Download source -  167.65 KB

Table of Contents

Introduction
Requirements

User Control Views
MDI Form Views
Modal Form Views
Different Views with Same Type
Notifications to Views
Base Views Implementations

Implementation

General Classes
WinformsViewsManager Class

Summary

Introduction

In the previous articles (parts 

1

 and 

2

), we have introduced a views manager concept for isolating the presentation mechanism

Hot News: 

10 Best Practices of Code

Commenting & Formatting

The Code Project Insider. 

Free each

morning.

 

PDFmyURL.com

background image

of the MVP Framework. This article describes the development of the real- life Windows Forms views manager and its attendant
classes for our MVP Framework.

The only responsibility of a views manager is switching between views. This might seem easy at first sight, however it
becomes more tricky as we delve deeper into the presentation specifics and take into account peculiarities of the views
mechanism. For example in the previous part we have already created a simple Windows Forms views manager, however it is
not able to treat user controls as views, neither can it handle dialogs or MDI forms.

That is why for creating a fully functional views manager we need to thoroughly analyz e the corresponding presentation
mechanism and construct requirements to that views manager. These requirements will typically include the description of
possible view types, their interrelation and so on. Thus our first step is building requirements to the constructed views manager.
We will assume that the basic requirements of working with simple forms are already implemented (see the end of the previous
article where we constructed a simple forms views manager) and proceed to the more advanced demands.

Requirements

User Control Views

The starting point for building the first requirement will be the fact that a user might want to have more than one interaction point
on his screen at a moment. Although separate, these views may be logically coupled, which discourages us from placing them
onto different forms. A more plausible (and popular in modern GUIs) solution is putting views into different parts of a single form.
For instance an orders view and an order lines view can be displayed as parts (e.g. upper and lower halves) of a common
window.

In .NET Windows Forms technology, such views are implemented as user controls. They are designed separately, but are
finally placed together and arranged on a single form. Thus in general our requirement sounds like this: 

UserControl

 class

descendants may be used as views.

To express this requirement in a more precise form, let us decide how a developer would mark a particular user control to be
used as a view. Here two alternatives are possible:

1.  Let the Framework create an instance of the user control
2.  Create the user control instance manually and place it on some view.

If a developer chooses 2 (to create an instance himself) then how will the Framework distinguish the user control- view from an
ordinary user control? The answer is quite obvious here: a user control class should implement the 

IView

 interface to make

the MVP Framework treat it as a view. So here is how the first use case looks:

 Collapse | Copy Code

User control views
    User: Create a UserControl subclass which implements the IView interface.
          Place its instance on some view. Assign a ViewName property to it.
    System: Find this user control and initialize it (tie to the controller,
            register in the system and so forth)

Here we have included the view name assignment to the user's actions. That is because a view initializ ation requires the

Related Articles

Building an MVP Framework for .NET.
Part 1: The Basics of MVC and MVP
Building an MVP Framework for .NET.
Part 2: Implementing Core
Functionality
Building an MVP Framework for .NET.
Part 4: Strongly Typed Associations
Architecture Guide: Windows Forms,
Generics, Auto- Mapper, Entity
Framework, Framework Design and
many more..
Part I: Unifying Web and Windows
Form design and layout
Universal Framework for Science and
Engineering -  Part 7: Virtual Reality at
Once
Designing a Windows Control -  Part 1
An Alpha Channel Composited
Windows Form with Designer Support
Universal Framework for Science and
Engineering -  Part 2: Regression

 

PDFmyURL.com

background image

knowledge of that view's name.

However the view registration and initializ ation are not the only necessary activities. We should also consider how a user
control view should be activated. Unlike forms user controls cannot be activated, instead they have a 

Focus() 

method which

moves in the input focus. However focusing a user control is of little use if the parent form is inactive, therefore we should also
assure the parent form activation:

 Collapse | Copy Code

Activating a user control view
    User: Trigger a user control view activation (via Navigator.Naviagate(.).
    System: Activate the parent form and Call the Focus() method on the
            user control view.

A manual user control view activation is possible too when a user clicks somewhere inside that user control. As a response the
system should perform navigation to this view:

 Collapse | Copy Code

Manual user control view activation
    End user: Click on a user control view (or somehow else move the focus
              inside it).
    System: Perform the navigation to this view.

MDI Form Views

Another kind of view we might want to use is the MDI form. Although slightly out of fashion nowadays, MDI forms may prove
useful in various applications. That is why the next requirement will concern the usage of MDI forms as views.

Applying MDI forms in .NET is simple: the only thing needed is to specify the parent form by setting its 

isMdiContainer

property to 

true 

and to set 

MdiParent 

property for all child forms. We could link child forms to the parent form instances

by ourselves, however it is not as easy since the MVP Framework and particularly the views manager itself creates forms and
holds their instances. The better approach is to somehow tell the Framework which views should act as MDI parents, and which
ones should be their children. A good way of doing so is applying a .NET attribute with necessary parameters to the view type,
like this: 

[WinformsView("ChildView", typeof(MainTask), MdiParent = "ParentView")]

. So here is

the next use case:

 Collapse | Copy Code

MDI form views
    User: Equip the form type with a WinformsView attribute with MdiParent
          or isMdiParent named parameters. Then at some point navigate to
          the corresponding view.
    System: Initialize the view as an MDI parent or child as specified.

With respect to the view activation mechanism, MDI forms behave the same way as simple forms do. So let us turn to the next
requirement.

Engineering -  Part 2: Regression
Design Your Soccer Engine, and
Learn How To Apply Design Patterns
(Observer, Decorator, Strategy and
Builder Patterns) -  Part I and II
Universal Framework for Science and
Engineering -  Part 9: Dynamics of
aggregates
Universal Framework for Science and
Engineering -  Part 5: Category theory
Universal Framework for Science and
Engineering -  Part 8: Digital Image
Processing
Introduction to Bellevue View Engine -
Part 1
Model View Controller, Model View
Presenter, and Model View ViewModel
Design Patterns
Universal Framework for Science and
Engineering -  Part 6: Determination of
Orbits of Artificial Satellites
The Raz or Framework :: Part 1 ::
Plugins/Extensibility
Introduction to Bellevue View Engine -
Part 2
Form Designer
Universal Framework for Science and
Engineering -  Part 3: Control systems.
Processing of signals.

 

PDFmyURL.com

background image

Modal Form Views

Modal forms (dialogs) are very useful if we want a user to interact with only one form until he closes it. In .NET a form modality
depends on the way in which it is shown. 

Form.Show() 

displays form in an ordinary (not modal) state, while

Form.ShowModal() 

displays it as modal. Anyway it is a job of the views manager to show forms, and we should somehow

indicate which forms to display as modal. As in the previous requirement we may use a .NET attribute with a named parameter

ShowModal: [WinformsView("ChildView", typeof(MainTask), ShowModal = true)]

. This is the use

case:

 Collapse | Copy Code

Modal form views
    User: Equip the form type with a WinformsView attribute with a ShowModal
          named parameter. Then navigate to the corresponding view.
    System: Show the form as modal by calling Form.ShowDialog().

Dif f erent Views with Same Type

Applying the 

[View("ViewName", ...)] 

or 

[WinformsView("ViewName", ...)] 

attribute to a view type we

specify the concrete view type for the interaction point with 

ViewName

 view name. But what if another view should be of the

same type? The answer is straightforward: allow users to specify several 

[(Winforms)View]

 attributes with different view

names for a single view type:

 Collapse | Copy Code

Different views with same type
    User: Equip a view type with several (Winforms)View attributes.
    System: Treat this as descriptions of different views with the
            same view type.

Notif ications to Views

It may be important for a view to react in a particular way when it gets (de)activated. For example a view may disable some
controls on it when it loses focus. A view may also need to perform some initializ ation steps when it is activated for the first time.
For this we need notifications to be sent to views whenever they are (de)activated or initializ ed (activated for the first time).

For handling a view (de)activation we might watch the change of the 

Task.CurrentViewName 

property. The view

initializ ation can be done in the 

IView.Controller 

setter method. Much more straightforward, however, is to have explicit

Activate(bool activate)

 and 

Initialize() 

operations, invoked by the views manager. These operations may

be placed in a separate 

INotifiedView 

interface.

 Collapse | Copy Code

Notifications to views
    User: Invoke navigation to/from a view that implements INotifiedView
          interface.
    System: Call Activate(true/false) on that view. Call Initialize() on

 

PDFmyURL.com

background image

            it if activated for a first time.

Base Views Implementations

Each form or user control we want to be a view should implement the 

IView 

interface. It would be convenient if the

Framework provides developers with base form and user control classes which already implement 

IView 

and even

INotifiedView 

interfaces. For example these could be 

WinFormView 

and 

WinUserControlView 

classes.

Now we have finished with building requirements and will proceed to the implementation phase.

Implementation

General Classes

First we will implement the 

WinformsView 

attribute with optional parameters as defined in the "MDI form views" and "Modal

form views" use cases:

 Collapse | Copy Code

[AttributeUsage(AttributeTargets.Class, AllowMultiple = 

true

)]

public

 

class

 WinformsViewAttribute : ViewAttribute

{
    ...
    

public

 WinformsViewAttribute(Type taskType, 

string

 viewName)

        : 

base

(taskType, viewName) { }

    

public

 WinformsViewAttribute() { }

    

public

 

bool

 ShowModal

    ...
    

public

 

bool

 IsMdiParent

    ...
    

public

 

string

 MdiParent

    ...
}

In the previous article, we have introduced the 

DefaultViewInfosProvider 

class for processing 

[View]

 attributes.

For each met 

[View] 

attribute it created a 

ViewInfo 

instance. Similarly we should treat 

[WinformsViewAttribute]

attributes, except for that 

WinformsViewInfo 

objects should be created instead of simple 

ViewInfo 

objects.

 Collapse | Copy Code

public

 

class

 WinformsViewInfosProvider : DefaultViewInfosProvider

{
    

protected

 

override

 ViewInfo newViewInfo(Type viewType, ViewAttribute viewAttr)

    {
        WinformsViewInfo viewInfo = 

new

 WinformsViewInfo(viewType);

 

PDFmyURL.com

background image

        

if

 (!(viewAttr 

is

 WinformsViewAttribute)) 

return

 viewInfo;

        viewInfo.IsMdiParent = (viewAttr 

as

 WinformsViewAttribute).IsMdiParent;

        viewInfo.MdiParent = (viewAttr 

as

 WinformsViewAttribute).MdiParent;

        viewInfo.ShowModal = (viewAttr 

as

 WinformsViewAttribute).ShowModal;

        

return

 viewInfo;

    }
}

public

 

class

 WinformsViewInfo : ViewInfo

{
    

public

 WinformsViewInfo(Type viewType) : 

base

(viewType)

    { }

    

public

 

bool

 ShowModal

    ...
    

public

 

bool

 IsMdiParent

    ...
    

public

 

string

 MdiParent

    ...
}

Notice that 

AllowMultiple = true

 is specified for the 

WinformsViewAttribute 

(as well as for the

ViewAttribute

). By doing so we meet the "Different views with same type" requirement.

One more simple requirement we will implement before proceeding to the more complicated ones is the "Base views
implementations" requirement. For that we will create 

Form 

and 

UserControl 

descendants and make them implement

IView 

and 

IWinformsView 

interfaces in the simplest way: with the use of virtual properties with backing fields and empty

virtual methods:

 Collapse | Copy Code

public

 

class

 WinFormView : Form, IView, IWinformsView

{
    

// IView and IWinformsView implementations with virtual

    

// methods and virtual properties with backing fields

    ...
}

public

 

class

 WinUserControlView : UserControl, IView, IWinformsView

{
    

// IView and IWinformsView implementations with virtual

    

// methods and virtual properties with backing fields

    ...
}

Winf ormsViewsManager Class

 

PDFmyURL.com

background image

WinformsViewsManager 

class will inherit from 

ViewsManagerBase 

-  the simplest 

IViewsManager

implementation:

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

    ...
    

public

 

override

 

void

 ActivateView(

string

 viewName)

    {
        IView view = FindOrCreateView(viewName);
        NotifyViewsOnActivation(view);
        

if

 (view 

is

 Form)

            ActivateFormView(view);
        

else

 

if

 (view 

is

 UserControl)

            ActivateUserControlView(view);
    }

In the 

ActivateView 

method above, we do the following: get already created view from an internal hash or create a new

one and activate this view in a manner depending on the view kind. Between these two steps we notify views about their
(de)activation in the 

NotifyViewsOnActivation(...) 

method -  this is required by the "Notifications to views" use

case:

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

    ...
    

private

 

void

 NotifyViewsOnActivation(IView activatedView)

    {
        IWinformsView prevActiveWFView = prevActiveView 

as

 IWinformsView;

        

if

 (prevActiveWFView != 

null

) prevActiveWFView.Activate(

false

);

        IWinformsView winformsView = activatedView 

as

 IWinformsView;

        

if

 (winformsView != 

null

) winformsView.Activate(

true

);

        prevActiveView = activatedView;
    }

FindOrCreateView(...) 

method instantiates views if they do not exist yet. 

Type 

information is taken from the

appropriate 

WinformsViewInfo 

object. Then, depending on the view type (form or user control), the corresponding view

initializ ation method is invoked:

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

    ...
    

private

 IView FindOrCreateView(

string

 viewName)

    {
        IView result = views[viewName] 

as

 IView;

        

if

 (result == 

null

)

        {
            WinformsViewInfo viewInf = ViewInfos[viewName] 

as

 WinformsViewInfo;

 

PDFmyURL.com

background image

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

as

 IView;

            result.ViewName = viewName;
            

if

 (result 

is

 UserControl)

                InitializeUserControlView(result 

as

 UserControl);

            

else

 

if

 (result 

is

 Form)

                InitializeFormView(result 

as

 Form, viewInf);

        }
        

return

 result;

    }

Below are the methods for user control and form initializ ation:

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

    ...
    

protected

 

virtual

 

void

 InitializeUserControlView(UserControl userControlView)

    {
        InitializeView(userControlView 

as

 IView);

        userControlView.Enter += 

new

 EventHandler(view_ActivatedManually);

        NotifyInitialize(userControlView 

as

 IView);

        InitializeChildViews(userControlView);
    }

    

protected

 

virtual

 

void

 InitializeFormView(Form form, WinformsViewInfo viewInf)

    {
        InitializeView(form 

as

 IView);

        form.Activated += 

new

 EventHandler(view_ActivatedManually);

        form.IsMdiContainer = viewInf.IsMdiParent;
        

string

 mdiParent = viewInf.MdiParent;

        

if

 (mdiParent != 

null

)

            form.MdiParent = views[mdiParent] 

as

 Form;

        NotifyInitialize(form 

as

 IView);

        InitializeChildViews(form);
    }

Both these methods use the 

InitializeView(...) 

and 

NotifyInitialize(...) 

methods which contain common

initializ ation steps regardless of the view type. 

InitializeView(...) 

binds together a view with its controller.

NotifyInitialize(...) 

sends an 

Initialize

 message to the view accordingly to the "Notifications to views"

requirement:

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

    ...
    

private

 

void

 InitializeView(IView view)

    {
        views[view.ViewName] = view;
        view.Controller = Navigator.GetController(view.ViewName);

 

PDFmyURL.com

background image

        view.Controller.View = view;
    }

    

private

 

void

 NotifyInitialize(IView view)

    {
        INotifiedView winformsView = view 

as

 INotifiedView;

        

if

 (winformsView != 

null

)

            winformsView.Initialize();
    }

Note that the 

InitializeFormView(...) 

method contains code specific to views represented as forms: if needed, it

makes a form MDI child or parent, thus satisfying the "MDI form views" requirement.

InitializeChildViews(...)

 is a method that searches for user control views inside a form or another user control

view. The search is done recursively, for found user control views, the user control- specific

InitializeUserControlView(...) 

method is called. By doing so we implement the "User control views" use case:

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

    ...
    

protected

 

void

 InitializeChildViews(Control container)

    {
        

foreach

 (Control c 

in

 container.Controls)

        {
            IView childView = c 

as

 IView;

            

if

 ((childView != 

null

) && (!IsInitialized(childView)))

                InitializeUserControlView(childView 

as

 UserControl);

            

else

                InitializeChildViews(c);
        }
    }

By handling the 

Enter 

event of user controls we meet the "Manual user control view activation" requirement:

 Collapse | Copy Code

    

private

 

void

 view_ActivatedManually(

object

 sender, EventArgs e)

    {
        Navigator.TryNavigateToView((sender 

as

 IView).ViewName);

    }

The last two methods left are the view activation methods 

ActivateFormView 

and 

ActivateUserControlView

. The

former shows and makes active a form view, taking into account that it could be configured as modal (and thus meeting the
"Modal form views" requirement):

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

 

PDFmyURL.com

background image

    ...
    

private

 

void

 ActivateFormView(IView view)

    {
        Form form = view 

as

 Form;

        WinformsViewInfo viewInf = ViewInfos[view.ViewName] 

as

 WinformsViewInfo;

        

if

 (viewInf.ShowModal)

        {
            

if

 (!form.Visible) form.ShowDialog();

        }
        

else

        {
            form.Show();
            form.Activate();
        }
    }

ActivateUserControlView(...) 

method not only focuses the user control but it firstly activates the parent of this

control, thus implementing the "Activating a user control view" use case:

 Collapse | Copy Code

public

 

class

 WinformsViewsManager : ViewsManagerBase

    ...
    

private

 

void

 ActivateUserControlView(IView view)

    {
        UserControl uc = view 

as

 UserControl;

        uc.Focus();
        uc.FindForm().Show();
        uc.FindForm().Activate();
    }

Summary

Throughout this article, we have been building a comprehensive Windows Forms views engine for the Model- View- Presenter
Framework. We have started with a list of requirements for the future views engine and then implemented these requirements in
the 

WinformsViewsManager 

class and other satellite classes. As a result these classes comprise a fully- functional views

engine suitable for various MVP applications with Windows Forms- based UI. However it is not restricted to further extend this
views engine tailoring it for specific needs.

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)

 

PDFmyURL.com

background image

Article Top

Sign Up

 to vote   Poor

Excellent

Vo t e

Se arch t his f o rum 

 

G o

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

T he Cub anP

7:23 29 Se p  ' 10  

Oleg Z hukov

13:50 30 Sep '10  

b o o g o 2

19:34  17 Jun ' 08  

Oleg Z hukov

6:05 20 Jun '08  

Ruben Chakhmakhchyan

3:56 27 Jun '08  

G re at  Art icle  BUT  ho w can i "in re al wo rld " t ake  ad vant ag e  o f  t his?

 

Re: Great Article BUT how can i "in real world" take advantage of this?

 

We b Use rCo nt ro lVie w?

 

Re: WebUserControlView?

 

Re: WebUserControlView?

 

 

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  1 2  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

Oleg Z hukov

8:27 27 Jun '08  

Me C+ +

10:26  19 Fe b  ' 08  

Oleg Z hukov

20:32 21 Feb '08  

GerhardKreuz er

10:10 29 Sep '08  

raz anp aul

4 :08 13 Fe b  ' 08  

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

1

2

 

Next »

 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

Re: WebUserControlView?

 

What  ab o ut  CAB?  

Re: What about CAB?

 

Re: What about CAB?

 

So urce  Co d e

 

 

PDFmyURL.com