Dear List:
Another poser. I am implementing an invoice form with child details. Everything works great until I save and rebind then the child seems to lose connection because it doesnt fire validation checking and no longer fires the PropertyChanged event on the parent Invoice object. I have a parent object, CurrentInvoice, which is assigned to InvoiceBindingSource and InvoiceDetails property assigned to InvoiceDetailsBindingSource. I am following the code in the new 3.0 projecttracker but am having difficulty after clicking an Apply button. Here is the code in the applicable areas:
Public
Sub New(ByVal Invoice As Invoice) ' This call is required by the Windows Form Designer.InitializeComponent()
' Add any initialization after the InitializeComponent() call.CurrentInvoice = Invoice
'_patientID = CurrentInvoice.PatientIDBindUI()
ApplyAuthorizationRules()
Me.btnSave.Enabled = False Me.btnApply.Enabled = False End Sub Public Sub ApplyAuthorizationRules() Implements RSSoftware.ScriptAssist.ObjectEdit.ApplyAuthorizationRules ' have the controls enable/disable/etc Me.ReadWriteAuthorization1.ResetControlAuthorization() Dim canEdit As Boolean = ScriptAssist.Invoice.CanEditObjectbtnApply.Enabled = canEdit
Me.btnSave.Enabled = canEdit Me.GridView1.OptionsBehavior.Editable = canEdit ' enable/disable appropriate buttons ' enable/disable role column in grid End Sub Public Sub BindUI() Implements RSSoftware.ScriptAssist.ObjectEdit.BindUICurrentInvoice.BeginEdit()
Me.InvoiceBindingSource.DataSource = CurrentInvoice End Sub Public Function RebindUI(ByVal Save As Boolean, ByVal Rebind As Boolean) As Boolean Implements RSSoftware.ScriptAssist.ObjectEdit.RebindUI ' disable events Me.InvoiceBindingSource.RaiseListChangedEvents = False Me.InvoiceDetailsBindingSource.RaiseListChangedEvents = False Try ' unbind the UIScriptAssist.Utilities.UnbindBindingSource(
Me.InvoiceDetailsBindingSource, Save, False)ScriptAssist.Utilities.UnbindBindingSource(
Me.InvoiceBindingSource, Save, True) Me.InvoiceDetailsBindingSource.DataSource = Me.InvoiceBindingSource ' save or cancel changes If Save ThenCurrentInvoice.ApplyEdit()
Try Dim temp As ScriptAssist.Invoice = CurrentInvoice.Clone()CurrentInvoice = temp.Save()
Catch ex As Csla.DataPortalException When TypeOf ex.BusinessException Is SqlClient.SqlException If CType(ex.BusinessException, SqlClient.SqlException).Class = 16 Then 'Most likely due to concurrency error - recommend closing drug and reopeningMessageBox.Show(
"This record has been changed in another window either on this machine or " _& Microsoft.VisualBasic.ControlChars.CrLf &
"on another client machine while this record was open. Click OK, make a note" _& Microsoft.VisualBasic.ControlChars.CrLf &
"of any changes you have made here you wish saved for this record, close this" _& Microsoft.VisualBasic.ControlChars.CrLf &
"window, the reopen this record in a new window and make the desired changes " _& Microsoft.VisualBasic.ControlChars.CrLf &
"finally saving the record.", "CONCURRENCY ERROR", MessageBoxButtons.OK, MessageBoxIcon.Stop) ElseMessageBox.Show(ex.BusinessException.ToString, _
"Error saving", MessageBoxButtons.OK, _MessageBoxIcon.Exclamation)
End If Catch ex As Csla.DataPortalExceptionMessageBox.Show(ex.BusinessException.ToString, _
"Error saving", MessageBoxButtons.OK, _MessageBoxIcon.Exclamation)
Catch ex As Csla.Validation.ValidationException Dim sMsg As New System.Text.StringBuilder("One or more fields have failed validation. Refer to any errors")sMsg.AppendLine(
" on this form and the following list: ")sMsg.AppendLine()
For Each BrokenRule As Csla.Validation.BrokenRule In CurrentInvoice.BrokenRulesCollectionsMsg.AppendLine(
" " & BrokenRule.Description) NextMessageBox.Show(sMsg.ToString,
"VALIDATION ERROR", MessageBoxButtons.OK, MessageBoxIcon.Exclamation) Catch ex As ExceptionMessageBox.Show(ex.ToString, _
"Error saving", MessageBoxButtons.OK, _MessageBoxIcon.Exclamation)
End Try ElseCurrentInvoice.CancelEdit()
End If Finally ' rebind UI if requested If Rebind ThenBindUI()
End If ' restore events Me.InvoiceBindingSource.RaiseListChangedEvents = True Me.InvoiceDetailsBindingSource.RaiseListChangedEvents = True If Rebind Then ' refresh the UI if rebinding Me.InvoiceBindingSource.ResetBindings(False) Me.InvoiceDetailsBindingSource.ResetBindings(False) End If End Try If CurrentInvoice.IsDirty = False And CurrentInvoice.IsValid = True Then Return True Else Return False End If End FunctionYour help and guidance is greatly appreciated.
Rob
CSLA automatically rehooks the PropertyChanged event so your list gets the event and raises a ListChanged event. It can do this because BusinessListBase manages the ownership of those child objects - it controls the references.
BusinessBase does not manage the reference from your root object to its children. You declare that field in your code, and so you are responsible for its management. This includes handling the ListChanged event so you know to raise the root's PropertyChanged event.
ProjectTracker doesn't do that, because the root object has no properties that derive from the state of its children. At some point I should probably add some data like that, so I can illustrate the concept.
However, you clearly have code to hook the event right? All you need to do is call that code when the root gets deserialized - which means overriding the OnDeserialized method that is declared by BusinessBase and rehooking the ListChanged event at that point.
Sweet, thanks Rocky.
Here is that overridden sub:
Protected Overrides Sub OnDeserialized(ByVal context As System.Runtime.Serialization.StreamingContext) MyBase.OnDeserialized(context) AddHandler _invoiceDetails.ListChanged, AddressOf _invoiceDetails_ListChanged End SubScriptAssist.Utilities.UnbindBindingSource(Me.InvoiceDetailsBindingSource, Save, False)
ScriptAssist.Utilities.UnbindBindingSource(Me.InvoiceBindingSource, Save, True)
Me.InvoiceDetailsBindingSource.DataSource = Me.InvoiceBindingSource
Copyright (c) Marimer LLC