Best way to do imported viewmodel menu parts?

Topics: UI Architecture
Nov 5, 2012 at 11:42 PM

I'm importing everything using mef and would like to wire up my menu's as individual parts that import into a menu viewmodel.  What i'm curious about is how best to tie the menu part viewmodel to the business object viewmodel. 

For instance, my business object viewmodel contains CanSave and CanDelete logic returning a bool.  And a Save and Delete methods.  The OnActivate is overridden to publish that it was activated:

    Protected Overrides Sub OnActivate()
        MyBase.OnActivate()
        Events.Publish(New ActivatedViewModelEvent(Of EmployeeDetailViewModel) With {.Value = Me})
    End Sub

I have a menu part viewmodel which is exported/imported into the shell viewmodel.  It subscribes to this event:

 

        AddHandler message.Value.PropertyChanged,
            Sub(sender As Object, e As PropertyChangedEventArgs)
                If e.PropertyName = "CanSave" Then
                    _isEnabled = message.Value.CanSave
                    NotifyOfPropertyChange(Function() IsEnabled)
                End If
            End Sub

 

This effectively enables/disables the Save Button on the menu depending on the business object viewmodel.  This works.

Now what i would like to do is fire an Execute command when the button is pressed.  The MenuPart viewmodel has an Execute method to do this.  My first thought was to hold a reference in the MenuPart viewmodel to the business object viewmodel like so:

    Public Overrides Sub Handle(message As ActivatedViewModel(Of EmployeeDetailViewModel))
        Me._viewMode = message.Value

        AddHandler message.Value.PropertyChanged,
            Sub(sender As Object, e As PropertyChangedEventArgs)
                If e.PropertyName = "CanSave" Then
                    _isEnabled = message.Value.CanSave
                    NotifyOfPropertyChange(Function() IsEnabled)
                End If
            End Sub

    End Sub

Then in the MenuPart viewmodel the Execute method would look like:

    Public Overrides Sub Execute()
            ViewModel.Save()
    End Sub

I think this would work okay, but i'm wondering if there's a better way of doing this?  I do not know much about memory utilization, but my fear is that holding a reference to the viewmodel via a property on the MenuPart viewmodel might eat up resources or cuase potential leaks.  Especially in light of the possibility of several menu parts.  And I'd like to avoid that.

However, this would allow me to wire up my menu parts in such a way that the business object view model is unaware of them.  And that seems like the way to go.

Feedback would be hugely appreciated.  Even a smartass comment about googling "Caliburn Micro Menu Event" or somesuch (but only if the results actually point me to a relevant answer).

Nov 6, 2012 at 10:09 PM

I'm now using this in my Handle on the menu part viewmodel:

    Public Overrides Sub Handle(message As ActivatedViewModel(Of EmployeeDetailViewModel))
        AddHandler message.Value.PropertyChanged,
            Sub(sender As Object, e As PropertyChangedEventArgs)
                If e.PropertyName = "CanSave" Then
                    Me.IsEnabled = message.Value.CanSave
                    NotifyOfPropertyChange(Function() IsEnabled)
                End If
            End Sub

        Act = Sub()
                  message.Value.BeginSave()
              End Sub
    End Sub

And my Execute method on the menu part viewmodel is (base class):

    Public Sub Execute() Implements IEmployeeMenuPart.Execute
        Act.DynamicInvoke()
    End Sub
I no longer require keeping a reference to the source viewmodel.  I'm new to delegates and not entirely sure how dynamicinvoke might impact things.  Do you see any issues with this implementation?