Question

I am trying to implement the MVP pattern in VBA for a winform as I wish to be able to reuse the same code for the model/presenter but be able to change the view (winform) for another one easily. I think I have the basics sorted out, however, as the forms are more like "settings" forms rather than say, "interactive" ones, I wish to return a collection of values from the form when it closes, but I am not sure which part (M, V or P) to put this logic in.

I was thinking to put it in the presenter and set it up as a property that I could access from elsewhere.

Here's my code so far (please bear in mind I am a beginner with patterns, and this code is simplified it somewhat):

Presenter:

Private model As IPlanningParametersModel
Private view As IPlanningParameterView

Public Sub Initialise(view As IPlanningParameterView, model As IPlanningParametersModel)
    Set model = model
    Set view = view
End Sub

Public Sub updateViewWthModel()
    Set view.PlanningParameters = model
End Sub

Public Sub updateModelWithView()
    Set model = view.PlanningParameters
End Sub

Model:

Private m_ParamDictionary As Scripting.Dictionary

Implements IPlanningParametersModel

Private Sub Class_Initialize()
    Set m_ParamDictionary = New Scripting.Dictionary
End Sub

Private Sub IPlanningParametersModel_Remove(ByRef Name As String)
    Me.Remove Name
End Sub

Private Sub IPlanningParametersModel_Add(ByRef PlanParam As IPlanningParameter)
    m_ParamDictionary.Add PlanParam
End Sub

Private Function IPlanningParametersModel_Item(ByRef Name As String) As IPlanningParameter
    Set IPlanningParametersModel_Item = m_ParamDictionary.Item(Name)
End Function

View:

Implements IPlanningParameterView

Private Function IPlanningParameterView_Show(Optional ByVal Modal As Boolean = True)
    If Modal Then Me.Show (vbModal) Else Me.Show (vbModeless)
End Function

Private Function IPlanningParameterView_Hide()
    Me.Hide
End Function

Private Property Let IPlanningParameterView_Caption(ByRef Value As String)
    Me.Caption = Value
End Property       

Private Property Get IPlanningParameterView_PlanningParameters() As IPlanningParametersModel
    'TODO: Cycle through each control in form to obtain configuration
    '      and add IPlanningParametersModel 
End Property

Private Property Set IPlanningParameterView_PlanningParameters() As IPlanningParametersModel
    'TODO: Cycle through each item in IPlanningParametersModel and set
    '      each control in form to reflect the configuration value
End Property

Finally the bit that connects them together:

Dim model As IPlanningParametersModel
Set model = New PlanningParametersModel

Dim view As IPlanningParameterView
Set view = New FPlanningParameterView

Dim pres As Presenter
Set pres = New Presenter
pres.Initialise view, model

So in this case I wish to actually use the values located in the model elsewhere in other code later on.

Should I add a new property to the Presenter part that just returns the model? E.g:

Public Property Get Settings() as IPlanningParametersModel
    Set Settings = model
End Property

I've tried to search for a solution to this, but there aren't many examples of MVP in VB6/VBA (in fact, the only decent one I found was here), nearly all are in .NET which sometimes doesn't translate that well back to classic VB since they use features not available.

Edit:

After having more time to think and research on this, I think what I need is a way to obtain and set data in the model directly rather than using the storage object that the model is sat upon. For example, in most examples of MVP, the model is a "facade" for a database or other repository which stores its data somewhere. The other parts of the program (i.e. outside the MVP) then query this database to obtain the information that the model was sat on. In this case, nothing accesses the model directly, the flow goes via the database which is almost "independent " of the rest of the program.

In my particular case, I do not really need an underlying database to store this information as I just need to be able to set and get the values that the model holds.

Edit 2

Perhaps I could implement the "database" for the model as a Singleton class and then pass this to the model's constructor when it's initiated? For example:

Dim model As IPlanningParametersModel
Set model = New PlanningParametersModel
Set model.DataStore = MySingleton

Dim view As IPlanningParameterView
Set view = New FPlanningParameterView

Dim pres As Presenter
Set pres = New Presenter
pres.Initialise view, model

The DataStore property of the model could use an interface and MySingleton would implement the same interface and then I could then use MySingleton outside of the above code. Does that sound reasonable?

Any other suggestions on this structure are welcome as this is my first attempt!

Was it helpful?

Solution

The only problem with exposing the model from the presenter is that whatever is using the presenter becomes tightly coupled to it.

I prefer my presenters to emit events to an Event Aggregator that then publishes to any subscribers. This keeps everything loosely coupled.

Don't know how well this might work in VB6, it's been a long time. However, if you went down this road, your presenter would emit an event when the model changes with the current model attached to the event.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top