Business Logic Framework - Tutorial 17:
This tutorial demonstrate the ability of business objects to fire events while different types of commands are being executed. The event model is consistent through out all types of commands. Each method fires an event before it executes the specified command and it fires a second event after it has executed the command. The first event that is fired before the command is executed gives the ability to cancel the command.
The following methods have events that can be handled:
- Load
- Find
- Update
- Insert
- Delete
In addition two additional events are fired by the business object when the object completes initialization, and another event is fired when the object is being disposed.
The following tutorial demonstrate these capabilities by taking the Find and Update methods as sample:
| private Customers Customer = null; | |
| private void Page_Load() | |
| { | |
| // Please note: This tutorial requires that the QO_SHOP sample database included with v 3.x. | |
| // If you have have the the database schema from a previous version of QO_SHOP please upgrade the | |
| // QO_SHOP database by using the Drop Objects.sql and Create Objects.sql. If you like the default | |
| // test data to be automatically inserted, please use the Insert Data.sql file. | |
| // The purpose of this tutorial is to demonstrate the ability of the business objects to fire events | |
| // at various stages. This tutorial will also demonstrate how an event handler can be used to cancel the command. | |
| // In this tutorial we will return a list of Customers, and the BeforeFind event will be handled and | |
| // extra search criteria will be applied to the business object. | |
| // If the user selects a customer record in the Grid, the Edit tab will gain focus, and the form will be pre filled | |
| // with the currently selected customer information. | |
| // If the user tries to update the customer record, the business object's BeforeUpdate event handler will be used to | |
| // request confirmation from the user. | |
| // In addition, the AfterFind and and AfterUpdate events will be captured, and they can be used to notify the user | |
| // of the result. | |
| if (this.Customer == null) | |
| { | |
| // if this Customer instance is null, create a new instance and wire up the event handlers. | |
| this.Customer = new Customers(); | |
| // The following line will hook the Customer_BeforeFind method to the BeforeFind event of the Customer object. | |
| this.Customer.BeforeFind += new BeforeCommandEventHandler(Customer_BeforeFind); | |
| // The following line will hook the Customer_BeforeUpdate method to the BeforeUpdate event of the Customer object. | |
| this.Customer.BeforeUpdate += new BeforeCommandEventHandler(Customer_BeforeUpdate); | |
| // The following line will hook the Customer_AfterFind method to the AfterFind event of the Customer object. | |
| this.Customer.AfterFind += new AfterCommandEventHandler(Customer_AfterFind); | |
| // The following line will hook the Customer_AfterUpdate method to the AfterUpdate event of the Customer object. | |
| this.Customer.AfterUpdate += new AfterCommandEventHandler(Customer_AfterUpdate); | |
| // Execute the Find method, and this will fire the BeforeFind and AfterFind event handlers in that order. | |
| this.Customer.Find(); | |
| // Check to see if there were any records returned by the Find method. If records were returned then we attach the ResultSet | |
| // property to the GridView1's DataSource property in order to display the data. | |
| if (this.Customer.AffectedRecords > 0) | |
| { | |
| this.GridView1.DataSource = this.Customer.ResultSet; | |
| this.GridView1.DataMember = this.Customer.GetResultSetName(); | |
| this.Button_Save.Enabled = false; | |
| } | |
| } | |
| } | |
| void Customer_AfterUpdate(object sender, AfterCommandEventArgs e) | |
| { | |
| // Event arguments passed are of type AfterCommandEventArgs. | |
| // This type of event arguments are used in all the events that are fired after a | |
| // command has been executed. | |
| // Success property of the event arguments can be used to check if the command was successful | |
| // or not. If the command was not success, there may be more information available in the ErrorString property. | |
| if (!e.Success) | |
| { | |
| MessageBox.Show("Your changes were not saved! \n " + e.BusinessObject.ErrorString); | |
| } | |
| else | |
| { | |
| MessageBox.Show("Changes Saved!"); | |
| } | |
| } | |
| void Customer_AfterFind(object sender, AfterCommandEventArgs e) | |
| { | |
| // It is relatively very easy to access the business objects and the status of the command. | |
| // Success property of the event arguments indicates if the command was successful or not. | |
| if (!e.Success) | |
| { | |
| MessageBox.Show("Search was not successful. \n " + e.BusinessObject.ErrorString); | |
| } | |
| else | |
| { | |
| // You can access properties of the business object by accessing the BusinessObject property of the event arguments. | |
| // The type of of the BusinessObject property is IBusinessObject. To access BusinessObject as the actual type just | |
| // case the BusinessObject property instance to the type of the object. | |
| MessageBox.Show("Your search returned " + e.BusinessObject.AffectedRecords.ToString() + " records."); | |
| } | |
| } | |
| void Customer_BeforeUpdate(object sender, BeforeCommandEventArgs e) | |
| { | |
| // We can check if the BusinessObject values that are being saved are valid or not based on the validation criteria | |
| // of the business object. | |
| if (!e.BusinessObject.IsValid) | |
| { | |
| // You can easily access the business object instance from the BusinessObject property of the event arguments. | |
| MessageBox.Show(e.BusinessObject.ErrorString); | |
| } | |
| else | |
| { | |
| DialogResult res = MessageBox.Show("Are you sure you want to save the changes?", "Do you want to Save?", MessageBoxButtons.YesNo); | |
| e.Cancelled = (res == DialogResult.No); | |
| } | |
| } | |
| void Customer_BeforeFind(object sender, BeforeCommandEventArgs e) | |
| { | |
| // Ask the user to specify the criteria he/she would like to search the customer table for. | |
| string criteria = Interaction.InputBox("Enter the value you would like to search the Customers table for?", "Search!", null, this.Left + 50, this.Top + 100); | |
| // If the user specified a criteria, then we set the customer object's field values accordingly. | |
| if (!String.IsNullOrEmpty(criteria)) | |
| { | |
| // Setting ObjectMode to ObjectModes.Search will cause business object to toggle the UseInSearch properties of the field's that are assigned a value. | |
| this.Customer.ObjectMode = ObjectModes.Search; | |
| // Setting MoreResults causes the business object to perform a loose search, and records where FirstName or LastName matches the "criteria" will be returned. | |
| this.Customer.MoreResults = true; | |
| // Setting the PartialTextMatch results in all StringField instances to perform a partial text search. Hence any records where the FirstName or LastName contain the search criteria | |
| // will be returned. | |
| this.Customer.PartialTextMatch = true; | |
| // Since the ObjectMode of the business object is set to ObjectModes.Search, setting the value of the FirstName and LastName fields will change their UseInSearch property to true. | |
| this.Customer.FirstName.Value = criteria; | |
| this.Customer.LastName.Value = criteria; | |
| } | |
| else | |
| { | |
| DialogResult res = MessageBox.Show("You did not specify any search criteria, are you sure you want to run the search without any criteria?", "Warning!", MessageBoxButtons.YesNo); | |
| e.Cancelled = (res == DialogResult.No); | |
| } | |
| } | |
| private void Tutorial17_Leave(object sender, EventArgs e) | |
| { | |
| // Since the user is leaving this screen it is time to dispose of the object. | |
| this.Customer.Dispose(); | |
| this.Customer = null; | |
| this.GridView1.DataSource = null; | |
| } | |
| private void Tutorial17_Enter(object sender, EventArgs e) | |
| { | |
| // User has just entered, so it is time to load the business object. | |
| this.Page_Load(); | |
| } | |
| private void GridView1_SelectionChanged(object sender, EventArgs e) | |
| { | |
| this.TextBox_FirstName.Text = ""; | |
| this.TextBox_LastName.Text = ""; | |
| // If the Customer object is not null and the user has selected at least one row, | |
| // then we can take the SelectedRows[0] and have the Customer object load these values. | |
| if (this.Customer != null && this.GridView1.SelectedRows.Count > 0) | |
| { | |
| // Lets set the IsLoaded property and this property value can be used later to ensure that | |
| // that Customer object is actually loaded with the values that are needed. | |
| // LoadFromDataRow gives you flexibility to load the object values from the data row. This will essentially | |
| // save a round trip to the database since the values are already available in the Grid. | |
| this.Customer.IsLoaded = this.Customer.LoadFromDataRow((this.GridView1.SelectedRows[0].DataBoundItem as DataRowView).Row); | |
| if (this.Customer.IsLoaded) | |
| { | |
| this.TextBox_FirstName.Text = this.Customer.FirstName.Value; | |
| this.TextBox_LastName.Text = this.Customer.LastName.Value; | |
| this.Button_Save.Enabled = true; | |
| } | |
| else | |
| { | |
| this.Button_Save.Enabled = false; | |
| } | |
| } | |
| else | |
| { | |
| this.Button_Save.Enabled = false; | |
| } | |
| } | |
| private void Button_Save_Click(object sender, EventArgs e) | |
| { | |
| if (this.Customer != null && this.Customer.IsLoaded) | |
| { | |
| // Setting ObjectMode to ObjectModes.Search will cause business object to toggle the UseInSearch properties of the field's that are assigned a value. | |
| this.Customer.ObjectMode = ObjectModes.Save; | |
| // Set the values of FirstName and LastName, and this will change the UseInSave property to true since the | |
| // ObjectMode of the business object is set to ObjectModes.Save; | |
| this.Customer.FirstName.Value = this.TextBox_FirstName.Text; | |
| this.Customer.LastName.Value = this.TextBox_LastName.Text; | |
| // Calling the Update method will fire the BeforeUpdate event handler where the user will be able to cancel the command if desired. | |
| this.Customer.Update(); | |
| } | |
| } | |
| Dim WithEvents Customer As Customers = Nothing | |
| Private Sub Page_Load() | |
| 'Please note: This tutorial requires that the QO_SHOP sample database included with v 3.x. | |
| 'If you have have the the database schema from a previous version of QO_SHOP please upgrade the | |
| 'QO_SHOP database by using the Drop Objects.sql and Create Objects.sql. If you like the default | |
| 'test data to be automatically inserted, please use the Insert Data.sql file. | |
| 'The purpose of this tutorial is to demonstrate the ability of the business objects to fire events | |
| 'at various stages. This tutorial will also demonstrate how an event handler can be used to cancel the command. | |
| 'In this tutorial we will return a list of Customers, and the BeforeFind event will be handled and | |
| 'extra search criteria will be applied to the business object. | |
| 'If the user selects a customer record in the Grid, the Edit tab will gain focus, and the form will be pre filled | |
| 'with the currently selected customer information. | |
| 'If the user tries to update the customer record, the business object's BeforeUpdate event handler will be used to | |
| 'request confirmation from the user. | |
| 'In addition, the AfterFind and and AfterUpdate events will be captured, and they can be used to notify the user | |
| 'of the result. | |
| If Me.Customer Is Nothing Then | |
| Me.Customer = New Customers() | |
| ' Execute the Find method, and this will fire the BeforeFind and AfterFind event handlers in that order. | |
| Me.Customer.Find() | |
| ' Check to see if there were any records returned by the Find method. If records were returned then we attach the ResultSet | |
| ' property to the GridView1's DataSource property in order to display the data. | |
| If Me.Customer.AffectedRecords > 0 Then | |
| Me.GridView1.DataSource = Me.Customer.ResultSet | |
| Me.GridView1.DataMember = Me.Customer.GetResultSetName() | |
| End If | |
| End If | |
| End Sub | |
| Private Sub Customer_AfterUpdate(ByVal sender As System.Object, ByVal e As AfterCommandEventArgs) Handles Customer.AfterUpdate | |
| ' Event arguments passed are of type AfterCommandEventArgs. | |
| ' This type of event arguments are used in all the events that are fired after a | |
| ' command has been executed. | |
| ' Success property of the event arguments can be used to check if the command was successful | |
| ' or not. If the command was not success, there may be more information available in the ErrorString property. | |
| If Not e.Success Then | |
| MessageBox.Show("Your changes were not saved! \n " & e.BusinessObject.ErrorString) | |
| Else | |
| MessageBox.Show("Changes Saved!") | |
| End If | |
| End Sub | |
| Private Sub Customer_AfterFind(ByVal sender As System.Object, ByVal e As AfterCommandEventArgs) Handles Customer.AfterFind | |
| ' It is relatively very easy to access the business objects and the status of the command. | |
| ' Success property of the event arguments indicates if the command was successful or not. | |
| If Not e.Success Then | |
| MessageBox.Show("Search was not successful. \n " & e.BusinessObject.ErrorString) | |
| Else | |
| ' You can access properties of the business object by accessing the BusinessObject property of the event arguments. | |
| ' The type of of the BusinessObject property is IBusinessObject. To access BusinessObject as the actual type just | |
| ' case the BusinessObject property instance to the type of the object. | |
| MessageBox.Show("Your search returned " & e.BusinessObject.AffectedRecords.ToString() & " records.") | |
| End If | |
| End Sub | |
| Private Sub Customer_BeforeUpdate(ByVal sender As System.Object, ByVal e As BeforeCommandEventArgs) Handles Customer.BeforeUpdate | |
| ' We can check if the BusinessObject values that are being saved are valid or not based on the validation criteria | |
| ' of the business object. | |
| If Not e.BusinessObject.IsValid Then | |
| ' You can easily access the business object instance from the BusinessObject property of the event arguments. | |
| MessageBox.Show(e.BusinessObject.ErrorString) | |
| Else | |
| Dim res As DialogResult = MessageBox.Show("Are you sure you want to save the changes?", "Do you want to Save?", MessageBoxButtons.YesNo) | |
| If res = DialogResult.No Then | |
| e.Cancelled = True | |
| End If | |
| End If | |
| End Sub | |
| Private Sub Customer_BeforeFind(ByVal sender As System.Object, ByVal e As BeforeCommandEventArgs) Handles Customer.BeforeFind | |
| 'Ask the user to specify the criteria he/she would like to search the customer table for. | |
| Dim criteria As String = Interaction.InputBox("Enter the value you would like to search the Customers table for?", "Search!", Nothing, Me.Left + 50, Me.Top + 100) | |
| ' If the user specified a criteria, then we set the customer object's field values accordingly. | |
| If Not String.IsNullOrEmpty(criteria) Then | |
| ' Setting ObjectMode to ObjectModes.Search will cause business object to toggle the UseInSearch properties of the field's that are assigned a value. | |
| Me.Customer.ObjectMode = ObjectModes.Search | |
| ' Setting MoreResults causes the business object to perform a loose search, and records where FirstName or LastName matches the "criteria" will be returned. | |
| Me.Customer.MoreResults = True | |
| ' Setting the PartialTextMatch results in all StringField instances to perform a partial text search. Hence any records where the FirstName or LastName contain the search criteria | |
| ' will be returned. | |
| Me.Customer.PartialTextMatch = True | |
| ' Since the ObjectMode of the business object is set to ObjectModes.Search, setting the value of the FirstName and LastName fields will change their UseInSearch property to true. | |
| Me.Customer.FirstName.Value = criteria | |
| Me.Customer.LastName.Value = criteria | |
| Else | |
| Dim res As DialogResult = MessageBox.Show("You did not specify any search criteria, are you sure you want to run the search without any criteria?", "Warning!", MessageBoxButtons.YesNo) | |
| If res = DialogResult.No Then | |
| e.Cancelled = True | |
| End If | |
| End If | |
| End Sub | |
| Private Sub Tutorial17_Leave(ByVal sender As System.Object, ByVal e As EventArgs) Handles Me.Leave | |
| ' Since the user is leaving this screen it is time to dispose of the object. | |
| Me.Customer.Dispose() | |
| Me.Customer = Nothing | |
| Me.GridView1.DataSource = Nothing | |
| End Sub | |
| Private Sub Tutorial17_Enter(ByVal sender As System.Object, ByVal e As EventArgs) Handles Me.Enter | |
| ' User has just entered, so it is time to load the business object. | |
| Me.Page_Load() | |
| End Sub | |
| Private Sub GridView1_SelectionChanged(ByVal sender As System.Object, ByVal e As EventArgs) Handles GridView1.SelectionChanged | |
| Me.TextBox_FirstName.Text = "" | |
| Me.TextBox_LastName.Text = "" | |
| ' If the Customer object is not null and the user has selected at least one row, | |
| ' then we can take the SelectedRows[0] and have the Customer object load these values. | |
| If Not Me.Customer Is Nothing And Me.GridView1.SelectedRows.Count > 0 Then | |
| ' Lets set the IsLoaded property and this property value can be used later to ensure that | |
| ' that Customer object is actually loaded with the values that are needed. | |
| Dim rowView As DataRowView = DirectCast(Me.GridView1.SelectedRows(0).DataBoundItem, DataRowView) | |
| Me.Customer.IsLoaded = Me.Customer.LoadFromDataRow(rowView.Row) | |
| If Me.Customer.IsLoaded Then | |
| Me.TextBox_FirstName.Text = Me.Customer.FirstName.Value | |
| Me.TextBox_LastName.Text = Me.Customer.LastName.Value | |
| Me.Button_Save.Enabled = True | |
| Else | |
| Me.Button_Save.Enabled = False | |
| End If | |
| Else | |
| Me.Button_Save.Enabled = False | |
| End If | |
| End Sub | |
| Private Sub Button_Save_Click(ByVal sender As System.Object, ByVal e As EventArgs) Handles Button_Save.Click | |
| If Not Me.Customer Is Nothing And Me.Customer.IsLoaded Then | |
| ' Setting ObjectMode to ObjectModes.Search will cause business object to toggle the UseInSearch properties of the field's that are assigned a value. | |
| Me.Customer.ObjectMode = ObjectModes.Save | |
| ' Set the values of FirstName and LastName, and this will change the UseInSave property to true since the | |
| ' ObjectMode of the business object is set to ObjectModes.Save | |
| Me.Customer.FirstName.Value = Me.TextBox_FirstName.Text | |
| Me.Customer.LastName.Value = Me.TextBox_LastName.Text | |
| ' Calling the Update method will fire the BeforeUpdate event handler where the user will be able to cancel the command if desired. | |
| Me.Customer.Update() | |
| End If | |
| End Sub | |
