ViewModel and Entity Property Change event not getting handled.

ViewModel and Entity Property Change event not getting handled.

Old forum URL: forums.lhotka.net/forums/t/10861.aspx


jamie.clayton posted on Wednesday, November 09, 2011

G'day,

I'm using csla 3.8.4. What have I done wrong for the BusinessBase(of MyBusObj) not to fire the PropertyChanged event when I use the Csla.WPF.ViewModel.  I've run out of ideas on how to resolve this.

Scenario

 I've create a custom ViewModel in VB to handle a customer requirement to prompt users if they make changes to a Business Object, but don't click on the save button.

Public Class PromptToSaveChangesViewModel(Of T As Csla.Core.BusinessBase)
        Inherits Csla.Wpf.ViewModel(Of T)

I created a simple WPF screen which uses this Csla.WPF.ViewModel to show a single business object. The WPF screen displays all the information and buttons are configured etc.

In the Business Object I've got a simple PropertyChanged handler that automatically sets 2 fields in the business object to the Date the records was changed and the name of the user who changed it.

Private Sub BO_PropertyChanged(ByVal sender As ObjectByVal e As System.ComponentModel.PropertyChangedEventArgsHandles Me.PropertyChanged
            If Me.IsDirty Then

               logger.Info(String.Format("BusinessBase(Of MyBusObj) - 
PropertyChanged Event fired for {0}"
, e.PropertyName.ToString))
                If e.PropertyName <> String.Empty Then                     Using (BypassPropertyChecks)                         SetTheLastUpdatedUserAndDateValues()                     End Using                 End If
             End If
End Sub

The problem is the underlying Entity Property Change event is not firing. See a simple logger I've added to all the _PropertyChanged events across all these layers.  It looks like the property is getting changed but at the entity level, there is a problem with the propertychanged event handler under the CSLA 3.8.4 ViewModelBase(of T) codebase.  I suspect its OnModelChanged or Model_PropertyChanged that's causing some sort of disconnect of event handlers, because the actual property is getting saved, but my custom BO_PropertyChanged event handler is not executing.

Here is a log of PropertyChanged events for a simple task to edit the "Company" field. What is missing is entries for when the code is ment to fire and change the two fields "BusinessBase(Of MyBusObj) - PropertyChanged Event fired for {Company}".

PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanCreate
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanCreate
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanDelete
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanDelete
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanFetch
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanFetch
WPF Window Contructor has loaded a BO passed into it by cloning and existing BO from a list.
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanSave
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanSave
ViewModel(of T) - PropertyChanged Event fired for CanSave
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanSave
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanCancel
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanCancel
ViewModel(of T) - PropertyChanged Event fired for CanCancel
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanCancel
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanCreate
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanCreate
ViewModel(of T) - PropertyChanged Event fired for CanCreate
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanCreate
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanFetch
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanFetch
ViewModel(of T) - PropertyChanged Event fired for CanFetch
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanFetch
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for Company
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for Company
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for Company
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for Company
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for Company
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for Company
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for Company
PromptToSaveChangesViewModel Save(ByVal sender As Object, ByVal e As Csla.Wpf.ExecuteEventArgs) event fired.
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for IsBusy
PromptToSaveChangesViewModel - PropertyChanged Event fired for IsBusy
ViewModel(of T) - PropertyChanged Event fired for IsBusy
WPF Window private withevents _ViewModel.PropertyChanged Event fired for IsBusy
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for IsBusy
PromptToSaveChangesViewModel - PropertyChanged Event fired for IsBusy
ViewModel(of T) - PropertyChanged Event fired for IsBusy
WPF Window private withevents _ViewModel.PropertyChanged Event fired for IsBusy
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanSave
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanSave
ViewModel(of T) - PropertyChanged Event fired for CanSave
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanSave
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanCancel
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanCancel
ViewModel(of T) - PropertyChanged Event fired for CanCancel
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanCancel
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanCreate
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanCreate
ViewModel(of T) - PropertyChanged Event fired for CanCreate
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanCreate
PromptToSaveChangesViewModel - MyBase.Model.PropertyChanged Event fired for CanFetch
PromptToSaveChangesViewModel - PropertyChanged Event fired for CanFetch
ViewModel(of T) - PropertyChanged Event fired for CanFetch
WPF Window private withevents _ViewModel.PropertyChanged Event fired for CanFetch
WPF Window Closed

JonnyBee replied on Thursday, November 10, 2011

jamie.clayton

Using (BypassPropertyChecks)                        
     SetTheLastUpdatedUserAndDateValues()                    
End Using

When you use BypassPropertyChecks the properties inside the using will not raise PropertyChanged event.

I would suggest to move this part of the code into the PropertyHasChanged method - you should not set properties in OnPropertyChanged event and expect to get PropertyChangedEvent for those properties as well.

(Here in C#)

    protected override void PropertyHasChanged(string propertyName)
    {
      base.PropertyHasChanged(property);
      
// set additional properties here if you like -
// may raise OnPropertyChanged manually for additional properties too.

LoadProperty(LastChangedUser, Thread.CurrentPrincipal.Identity.Name);
LoadProperty(LastChanged, DateTime.Now);

OnPropertyChanged(LastChangedUser.Name);
OnPropertyChanged(LastChanged.Name);
            }

jamie.clayton replied on Thursday, November 10, 2011

Jonny,

Thanks for that coding style example.  It is a very elegant solution to a problem I hadn't resolved through my CSLA based solutions since I started in the 2.0 days.  I'll be refactoring a stack of code based on this!

Interestingly all the code I've been creating to override the ViewModel uses that exact style. Kicking myself :) for missing this.  If your ever in Australia, I would be happy to buy you a drink or 5. 

Copyright (c) Marimer LLC