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!