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.
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 Object, ByVal e As System.ComponentModel.PropertyChangedEventArgs) Handles Me.PropertyChanged If Me.IsDirty Then
logger.Info(String.Format("BusinessBase(Of MyBusObj) -If e.PropertyName <> String.Empty Then Using (BypassPropertyChecks) SetTheLastUpdatedUserAndDateValues() End Using End If
PropertyChanged Event fired for {0}", e.PropertyName.ToString))
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 |
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);
}
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