I am new to MVVM and struggling with some concepts, in particular how to pass values between viewmodels and keep them in sync as property values change.
Take the following scenario, where there are three levels of ViewModel.
JobVM - JobItemsVM - ProductListVM
Each VM is exposed as a property of it's parent. The ProductList contains a ClientID property to filter the list of available products by client. The top level job also contains a ClientID property which identifies who the client for the job is.
Now, what I want to do is for the pick list to react to any change in the client of the top level job (i.e. ProductList.ClientID = Job.ClientID).
I am using MVVMLight. Is using messaging an appropriate solution?
Below is some cut-down code of the classes involved which hopefully helps explain how I currently have things. The question is how can I "synchronise" the JobViewModel.CoreDataEntity.ClientID property with the PickList.FilterClientID property, and trigger PickList.LoadList(true) if JobViewModel.CoreDataEntity.ClientID is changed by the user. Or should I be approaching the whole thing differently?
CODE:
This is the business object representing a job, which includes a ClientID property which is the client assigned to the job
Public Class Job
Implements BLL.Base.ICoreDataEntity
Public Property JobID Implements BLL.Base.ICoreDataEntity.RecordID
Public Property ClientID
End Class
This is the primary view model for the job form, used to display and edit a job and its related records.
Public Class JobViewModel
'THIS PROPERTY HOLDS THE JOB BUSINESS OBJECT
Public Property CoreDataEntity As BLL.Base.ICoreDataEntity
'THIS CONTAINS ADDITIONAL VIEWMODELS USED TO MANAGE SUBLISTS (E.G. JOB ITEMS, COMMUNICATIONS)
Public Property SecondaryDataEntities As List(Of SecondaryDataVMHelper)
Public Sub New(recordID As Integer, enableEdit As Boolean)
'POPULATE THE COREDATAENTITY WITH A JOB FROM THE DATABASE
CoreDataEntity = New BLL.Jobs.Job(recordID)
'initialize secondary view models
Me.SecondaryDataEntities.Add(New SecondaryDataVMHelper(EntityTypes.JobItem))
Me.SecondaryDataEntities.Add(New SecondaryDataVMHelper(EntityTypes.Communication))
'pass down selected details from parent record to secondary view models
'NOTE - I COULD PASS DOWN THE CLIENT ID HERE AS WELL BUT WHAT IF CLIENTID CHANGES AFTER INITIALIZED?
For Each x As SecondaryDataVMHelper In SecondaryDataEntities
x.ParentRecordID = CoreDataEntity.RecordID
x.ParentEntityType = EntityTypes.Job
x.ParentRecordDescription = CoreDataEntity.ToString()
Next
End Sub
End Class
This viewmodel is used to manage a "sub list" related to a parent jobs (e.g. line items on a job)
Public Class SecondaryDataVMHelper
'THIS PROPERTY TELLS US WHAT TYPE OF RECORD WE ARE DEALING WITH IN THE SUB LIST
'FOR INSTANCE, JOB ITEMS
Public Property EntityType As EntityTypes
'AN ADDITIONAL VIEWMODEL TO MANAGE A "PICK LIST" WHICH CAN BE USED TO ADD ITEMS
'FOR INSTANCE, A PRODUCT LIST
Public Property PickList As PickListViewModel
Public Sub New(entityType As EntityTypes)
'SET UP WHAT TYPE OF DATA WE ARE DEALING WITH
Me.EntityType = entityType
'INITIALIZE THE APPROPRIATE PICK LIST
PickList = New PickListViewModel()
End Sub
End Class
And finally this viewmodel is used to manage a "pick list" displayed to the user
Public Class PickListViewModel
'THE CLIENT TO FILTER THE PICK LIST BY (E.G. ONLY SHOW PRODUCTS RELATING TO THAT CLIENT)
Public Property FilterClientID As Integer
'THIS STORES THE LIST POPULATED FROM THE DATABASE WHICH IS DISPLAYED IN THE UI
Public Property Records As ObservableCollection(Of Product)
'JUST TO TRACK IF THE PICK LIST HAS BEEN LOADED
Public Property IsLoaded As Boolean
Public Sub LoadList(forceReload As Boolean)
If forceReload = False And IsLoaded Then Exit Sub
Records = BLL.Products.GetLiveList(FilterClientID) 'LOAD THE DATA, FILTERING BY CLIENT
IsLoaded = True
End Sub
End Class