Products

Solutions

Resources

Partners

Community

About

New Community Website

Ordinarily, you'd be at the right spot, but we've recently launched a brand new community website... For the community, by the community.

Yay... Take Me to the Community!

The Community Blog is a personal opinion of community members and by no means the official standpoint of DNN Corp or DNN Platform. This is a place to express personal thoughts about DNNPlatform, the community and its ecosystem. Do you have useful information that you would like to share with the DNN Community in a featured article or blog? If so, please contact .

The use of the Community Blog is covered by our Community Blog Guidelines - please read before commenting or posting.


MVP Module Development – IModuleView, ModuleView and ModulePresenter

This article is cross-posted from my personal blog.

In an earlier blog I mentioned that since DotNetNuke 5.3, we have supported MVP (Model View Presenter) style Module Development using the WebForms MVP project as a basis.  In this blog  I will begin to explore how we can use the new DotNetNuke base classes ModulePresenter and ModuleView to build fully testable modules.

There are four components for each MVP Module Control.

  1. An Interface which defines the View
  2. A Model class which will be passed between the Presenter and the View
  3. A Concrete View class (the User Control which renders the content to the Response stream) and
  4. A Presenter Class which manages everything

As an example lets look at the code for the Taxonomy Manager module.  This module was first included in DNN 5.3, but it will be updated/refactored in DNN 5.4 (as we made a few changes to the base classes), so the code examples in this blog are from the latest source code.

IVocabularyListView Interface

We will start with the Interface which defines the View (Listing 1).

Listing 1: The IVocabularyListView Interface

   1:  Public Interface IVocabularyListView
   2:      Inherits IModuleView(Of VocabularyListModel)
   3:   
   4:      Event AddVocabulary As EventHandler
   5:   
   6:      Sub ShowAddButton(ByVal showButton As Boolean)
   7:  End Interface

The first thing to notice is that the Interface inherits from the IModuleView(Of VocabularyListModel) interface.  IModuleView(Of T) is a base interface for all DotNetNuke Modules (Listing 2).

Listing 2: The IModuleView(Of T) Interface

   1:  Public Interface IModuleView(Of T As {Class, New})
   2:      Inherits IView(Of T)
   3:   
   4:      Event Initialize As EventHandler
   5:   
   6:      Sub ProcessModuleLoadException(ByVal ex As Exception)
   7:   
   8:      Sub ShowMessage(ByVal messageHeader As String, ByVal message As String, _
   9:                      ByVal messageType As ModuleMessageType)
  10:  End Interface

As long as Module Developers create their concrete Views by inheriting from the base View class (ModuleView) they do not have to implement the three members of this base Interface, as these are implemented in the base class.

The important thing to learn from both these listings is that in general the interfaces contain only methods and events (actions) – no properties (state).  The Model class provides any state information.

VocabularyListModel Class

We now turn to the model.  This class contains anything that we need to move from the Presenter to the View.  In the case of the VocabularyListModel, it has three properties (Listing 3)

Listing 3: The VocabularyListModel Class

   1:  Public Class VocabularyListModel
   2:   
   3:      Private _IsEditable As Boolean
   4:      Private _NavigateUrlFormatString As String
   5:      Private _Vocabularies As IList(Of Vocabulary)
   6:   
   7:      Public Property IsEditable() As Boolean
   8:          Get
   9:              Return _IsEditable
  10:          End Get
  11:          Set(ByVal value As Boolean)
  12:              _IsEditable = value
  13:          End Set
  14:      End Property
  15:   
  16:      Public Property NavigateUrlFormatString() As String
  17:          Get
  18:              Return _NavigateUrlFormatString
  19:          End Get
  20:          Set(ByVal value As String)
  21:              _NavigateUrlFormatString = value
  22:          End Set
  23:      End Property
  24:   
  25:      Public Property Vocabularies() As IList(Of Vocabulary)
  26:          Get
  27:              Return _Vocabularies
  28:          End Get
  29:          Set(ByVal value As IList(Of Vocabulary))
  30:              _Vocabularies = value
  31:          End Set
  32:      End Property
  33:   
  34:  End Class

The three properties are:

  1. IsEditable – a boolean property that indicates that the current user has “Edit” rights – we will set this in the presenter and use its value in the View to optionally render ane “Edit” hyperlink column.
  2. NavigateUrlFormatString – a string property that we can set in the Presenter and is used in the View to generate the correct hyperlink for the Vocabulary row.
  3. Vocabularies – a list of Vocabulary objects that we will bind to a grid in the View.

VocabularyListPresenter Class

The VocabularyListPresenter Class controls the action.  As can be seen in Listing 4 it inherits from the ModulePresenter base class.  The base class is a Generic Type, taking two type parameters – the View Interface – IVocabularyListView and the Model VocabularyListModel.

Listing 4: The VocabularyListPresenter Class

   1:  Public Class VocabularyListPresenter
   2:      Inherits ModulePresenter(Of IVocabularyListView, VocabularyListModel)
   3:   
   4:      Private _VocabularyController As IVocabularyController
   5:   
   6:      Public Sub New(ByVal view As IVocabularyListView)
   7:          Me.New(view, New VocabularyController(New DataService()))
   8:      End Sub
   9:   
  10:      Public Sub New(ByVal listView As IVocabularyListView, _
  11:                     ByVal vocabularyController As IVocabularyController)
  12:          MyBase.New(listView)
  13:          Arg.NotNull("vocabularyController", vocabularyController)
  14:   
  15:          _VocabularyController = vocabularyController
  16:   
  17:          AddHandler View.AddVocabulary, AddressOf AddVocabulary
  18:   
  19:      End Sub
  20:   
  21:      Protected Overrides Sub OnInit()
  22:          MyBase.OnInit()
  23:   
  24:          View.Model.Vocabularies = (From v In _VocabularyController.GetVocabularies() _
  25:                                    Where v.ScopeType.ScopeType = "Application" _
  26:                                    OrElse v.ScopeType.ScopeType = "Portal" _
  27:                                    AndAlso v.ScopeId = PortalId _
  28:                                    Select v) _
  29:                                    .ToList()
  30:   
  31:          View.Model.IsEditable = IsEditable
  32:          View.Model.NavigateUrlFormatString = NavigateURL(TabId, _
  33:                                                      "EditVocabulary", _
  34:                                                      String.Format("mid={0}", ModuleId), _
  35:                                                      "VocabularyId={0}")
  36:      End Sub
  37:   
  38:      Protected Overrides Sub OnLoad()
  39:          MyBase.OnLoad()
  40:   
  41:          View.ShowAddButton(IsEditable)
  42:      End Sub
  43:   
  44:      Public Sub AddVocabulary(ByVal sender As Object, ByVal e As EventArgs)
  45:          Response.Redirect(NavigateURL(TabId, _
  46:                                        "CreateVocabulary", _
  47:                                        String.Format("mid={0}", ModuleId)))
  48:      End Sub
  49:   
  50:  End Class

The first constructor is required by the "WebFormsMvp” framework as the framework uses this constructor to bind the View and the Presenter together.  The presenter class uses an IVocabularyController instance to work with the business layer (API), and the second constructor allows us to pass an arbitrary IVocabularyController instance - for example, when testing.

If we look back at Listing 1, the IVocabularyListView Interface has a single method – ShowAddButton - and a single Event – AddVocabulary.  We “wire up” the event to a method in our Presenter in Line 17. 

Both the OnInit and OnLoad methods override methods in the base class.  These methods are “wired" up” in the base class to respond to the OnLoad and OnInit methods of the Page Lifecycle.

In OnInit we set all of the properties of the Model and in OnLoad we call the ShowAddButton of the View Interface to display the “Add Vocabulary” button.

Finally in the AddVocabulary EventHandler we can redirect control to the “CreateVocabulary” control.

Experienced Module Developers will notice that the code we have in the VocabularyListPresenter is essentially the same code we would normally create in the code-behind file of a standard ASP.NET User Control. 

The advantage of placing the code in the presenter class is that we can test it.  I will go into the testing aspects in a future blog, but first lets complete the review of the pattern by reviewing the concrete View class.

VocabularyList Class

The code behind file for the VocabularyList User Control is shown in Listing 5.

Listing 5: The VocabularyList Class

   1:  GetType(VocabularyListPresenter))> _
   2:  Partial Public Class VocabularyList
   3:      Inherits ModuleView(Of VocabularyListModel)
   4:      Implements IVocabularyListView
   5:   
   6:      Public Event AddVocabulary(ByVal sender As Object, ByVal e As EventArgs) _
   7:                          Implements IVocabularyListView.AddVocabulary
   8:   
   9:      Public Sub ShowAddButton(ByVal showButton As Boolean) _
  10:                          Implements IVocabularyListView.ShowAddButton
  11:          addVocabularyButton.Visible = showButton
  12:      End Sub
  13:   
  14:      Private Sub addVocabularyButton_Click(ByVal sender As Object, ByVal e As System.EventArgs) _
  15:                          Handles addVocabularyButton.Click
  16:          RaiseEvent AddVocabulary(Me, e)
  17:      End Sub
  18:   
  19:      Private Sub vocabulariesGrid_PreRender(ByVal sender As Object, ByVal e As System.EventArgs) _
  20:                          Handles vocabulariesGrid.PreRender
  21:          Dim hyperlinkColumn As DnnGridHyperlinkColumn = TryCast(vocabulariesGrid.Columns(0),  _
  22:                                                              DnnGridHyperlinkColumn)
  23:          If hyperlinkColumn IsNot Nothing Then
  24:              hyperlinkColumn.Visible = Model.IsEditable
  25:              hyperlinkColumn.DataNavigateUrlFormatString = Model.NavigateUrlFormatString
  26:          End If
  27:   
  28:      End Sub
  29:  End Class

Lines 1-4 are the most important part and they are required for the WebFormsMVP framework to “wire-up” the view to the presenter.  The PresenterBinding attribute tells the framework that this view should be bound to the VocabularyListPresenter presenter.  The View must inherit from the ModuleView(Of VocabularyListModel) base class and it must implement the IVocabularyListView interface.

Line 6 implements the Event AddVocabulary defined in the IVocabularyListView interface, and lines 9-12 implement the ShowAddButton method of the interface.

We try and keep the code in this class to a minimum as it is not testable, so the ShowAddButton method simply sets the visibility of the addVocabularyButton button. 

Lines 14-17 handle the click event of the addVocabularyButton button and it in turn raises the AddVocabulary Event. Our presenter is already setup to handle this event.

Finally in lines 19-28, we handle the PreRender event of the grid.  In this method we set two properties of the hyperlink Column depending on values of the properties of the Model.

This blog was just an overview of the important classes of the MVP implementation in DNN 5.3/4.  In future blogs I will dig deeper into the base classes and what they offer module developers, and show how you can write tests for your presenters.

Comments

There are currently no comments, be the first to post one.

Comment Form

Only registered users may post comments.

NewsArchives


Aderson Oliveira (22)
Alec Whittington (11)
Alessandra Daniels (3)
Alex Shirley (10)
Andrew Hoefling (3)
Andrew Nurse (30)
Andy Tryba (1)
Anthony Glenwright (5)
Antonio Chagoury (28)
Ash Prasad (37)
Ben Schmidt (1)
Benjamin Hermann (25)
Benoit Sarton (9)
Beth Firebaugh (12)
Bill Walker (36)
Bob Kruger (5)
Bogdan Litescu (1)
Brian Dukes (2)
Brice Snow (1)
Bruce Chapman (20)
Bryan Andrews (1)
cathal connolly (55)
Charles Nurse (163)
Chris Hammond (213)
Chris Paterra (55)
Clint Patterson (108)
Cuong Dang (21)
Daniel Bartholomew (2)
Daniel Mettler (181)
Daniel Valadas (48)
Dave Buckner (2)
David Poindexter (12)
David Rodriguez (3)
Dennis Shiao (1)
Doug Howell (11)
Erik van Ballegoij (30)
Ernst Peter Tamminga (80)
Francisco Perez Andres (17)
Geoff Barlow (12)
George Alatrash (12)
Gifford Watkins (3)
Gilles Le Pigocher (3)
Ian Robinson (7)
Israel Martinez (17)
Jan Blomquist (2)
Jan Jonas (3)
Jaspreet Bhatia (1)
Jenni Merrifield (6)
Joe Brinkman (274)
John Mitchell (1)
Jon Henning (14)
Jonathan Sheely (4)
Jordan Coopersmith (1)
Joseph Craig (2)
Kan Ma (1)
Keivan Beigi (3)
Kelly Ford (4)
Ken Grierson (10)
Kevin Schreiner (6)
Leigh Pointer (31)
Lorraine Young (60)
Malik Khan (1)
Matt Rutledge (2)
Matthias Schlomann (16)
Mauricio Márquez (5)
Michael Doxsey (7)
Michael Tobisch (3)
Michael Washington (202)
Miguel Gatmaytan (3)
Mike Horton (19)
Mitchel Sellers (40)
Nathan Rover (3)
Navin V Nagiah (14)
Néstor Sánchez (31)
Nik Kalyani (14)
Oliver Hine (1)
Patricio F. Salinas (1)
Patrick Ryan (1)
Peter Donker (54)
Philip Beadle (135)
Philipp Becker (4)
Richard Dumas (22)
Robert J Collins (5)
Roger Selwyn (8)
Ruben Lopez (1)
Ryan Martinez (1)
Sacha Trauwaen (1)
Salar Golestanian (4)
Sanjay Mehrotra (9)
Scott McCulloch (1)
Scott Schlesier (11)
Scott Wilkinson (3)
Scott Willhite (97)
Sebastian Leupold (80)
Shaun Walker (237)
Shawn Mehaffie (17)
Stefan Cullmann (12)
Stefan Kamphuis (12)
Steve Fabian (31)
Steven Fisher (1)
Tony Henrich (3)
Torsten Weggen (3)
Tycho de Waard (4)
Vicenç Masanas (27)
Vincent Nguyen (3)
Vitaly Kozadayev (6)
Will Morgenweck (40)
Will Strohl (180)
William Severance (5)
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out
What is Liquid Content?
Find Out