Is this the correct way to recall an event handler?

pachjo

Newcomer
Joined
Dec 27, 2006
Messages
23
I have made a button click handler to be generic to enable it to handle two buttons.

One button saves a record to the transactions table and the other to the transactions_weekly table.

Now if the record begin saved when running a call to the event handler for the transactions is of type "SHOPPING" the app prompts the user to ask do they want it also saved to the transactions_weekly table.

If the answer is yes I believe I need to recall the event handler I am currently in?

So to do this I create an object reference to the button on the form that would save a transaction_weekly record and then call the click event and pass it the reference object.

Problem is the error appears saying that objSender is not initialised when an attempt is made to reference it?

Am on on the right track or totally off beam?

Code:
    Private Sub btnSaveTransaction_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) _
    Handles btnSaveTransaction1.Click, btnSaveTransaction2.Click
 
        ' check to see if a valid entry has been made
 
        If Not ValidateEntry(sender) Then
 
            Exit Sub
 
        End If
 
        ' create a control object to access the name of the button making the call
 
        Dim ctlSender As Control = DirectCast(sender, System.Windows.Forms.Control)
 
        ' controls to make this sub generic
 
        Dim ctlDateTimePicker As New DateTimePicker, ctlComboBox As New ComboBox, ctlTextBox As New TextBox
 
        Dim ctlCheckBox1 As New CheckBox, ctlCheckBox2 As New CheckBox
 
        ' create an SQL command object to write changes to the database
 
        Dim cmdTransactions As New System.Data.SqlClient.SqlCommand
 
        ' string to pass table name to dynamic sql
 
        Dim strTableName As String = ""
 
        ' object to reference the save button on the transactions weekly page
 
        Dim objSender As Object = DirectCast(Me.Controls("btnSaveTransaction2"), Object)
 
        ' query callers name to setup the sql staement and controls
 
        Select Case ctlSender.Name
 
            Case "btnSaveTransaction1"
 
                strTableName = "transactions"
 
                cmdTransactions.CommandText = "INSERT INTO transactions (tran_date, tran_id, tran_amount, tran_balance, tran_save, " & _
                                              "tran_withdrawal) VALUES (@TransDate, @TransDesc, @TranAmount, 0, @Saved, @WithDraw)"
 
                ctlDateTimePicker = Me.dtmTransDate1
 
                ctlComboBox = Me.cboTransDescription1
 
                ctlTextBox = Me.txtAmount1
 
                ctlCheckBox1 = Me.chkSave
 
                ctlCheckBox2 = Me.chkWithDraw
 
                ' detailed monthly has these but detailed weekly does not
 
                cmdTransactions.Parameters.Add("@Saved", SqlDbType.Decimal).Value = ctlCheckBox1.Checked
 
                cmdTransactions.Parameters.Add("@WithDraw", SqlDbType.Decimal).Value = ctlCheckBox2.Checked
 
                ' when the transaction type is shopping ask do we want to save to transactions weekly also
 
                If ctlComboBox.Text = "SHOPPING" Then
 
                    If MessageBox.Show("Do you want this transaction written to the weekly transaction page", _
                                       "Copy Transaction", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) _
                                       = Windows.Forms.DialogResult.Yes Then
 
                        ' set the fields on the transactions weekly page to the ones on the transaction page
                        ' so when we call this event handler the values will be there as if the user had entered them
 
                        Me.dtmTransDate2.Text = ctlDateTimePicker.Text
 
                        Me.txtAmount2.Text = ctlTextBox.Text
 
                        Me.cboTransDescription2.Text = ctlComboBox.Text
 
                        ' simulate the user clicking the save button on the transactions weekly page
 
                        btnSaveTransaction_Click(objSender, e)
 
                        ' reset the transactions weekly fields
 
                        Me.dtmTransDate2.Text = Now.ToString
 
                        Me.txtAmount2.Text = ""
 
                    End If
 
                End If
 
            Case "btnSaveTransaction2"
 
                strTableName = "transactions_weekly"
 
                cmdTransactions.CommandText = "INSERT INTO transactions_weekly (tran_date, tran_id, tran_amount, tran_balance) " & _
                                              "VALUES (@TransDate, @TransDesc, @TranAmount, 0)"
 
                ctlDateTimePicker = Me.dtmTransDate2
 
                ctlComboBox = Me.cboTransDescription2
 
                ctlTextBox = Me.txtAmount2
 
        End Select
 
        Try
 
            ' link the command to the database connection
 
            cmdTransactions.Connection = glb_cnMB2007
 
            ' add the parameters to the command
 
            cmdTransactions.Parameters.Add("@TransDate", SqlDbType.DateTime).Value = ctlDateTimePicker.Text
 
            cmdTransactions.Parameters.Add("@TransDesc", SqlDbType.VarChar).Value = ctlComboBox.SelectedValue.ToString
 
            cmdTransactions.Parameters.Add("@TranAmount", SqlDbType.Decimal).Value = ctlTextBox.Text
 
            ' if the record was appended successfully then update the transaction display
 
            If cmdTransactions.ExecuteNonQuery() = 1 Then
 
                ' refresh the rolling balance in transaction table
 
                CalculateRollingBalance(strTableName)
 
                If Not RefreshTransactionLists(Me.tbcMain.SelectedIndex) Then
 
                    Me.Controls("btnSaveTransaction" & Me.tbcMain.SelectedIndex).Enabled = False
 
                    Me.Controls("btnClearTransaction" & Me.tbcMain.SelectedIndex).Enabled = False
 
                End If
 
            End If
 
            ' reset the transaction fields
 
            ctlDateTimePicker.Value = Now
 
            ctlTextBox.Text = ""
 
            ctlTextBox.Select()
 
        Catch objError As Exception
 
            ' tell user no connection made
 
            MessageBox.Show("Failed to save transaction to the database" & vbCrLf & vbCrLf & objError.Message, _
"Save Error", MessageBoxButtons.OK, MessageBoxIcon.Error)
 
        End Try
 
    End Sub
 
Rather than explicity calling the btnSaveTransaction_Click(objSender, e) method directly you might want to use the PerformClick on the btnSaveTransaction2 control.

Also I notice you are creating a lot of controls in the code i.e.
Visual Basic:
Dim ctlDateTimePicker As New DateTimePicker, ctlComboBox As New ComboBox, ctlTextBox As New TextBox
Dim ctlCheckBox1 As New CheckBox, ctlCheckBox2 As New CheckBox
if you are going to assign existing controls to these variables you do not need the New keyword - this will prevent you creating the unused instances of the controls and will keep the memory utilisation down.

In the line
Visual Basic:
Dim objSender As Object = DirectCast(Me.Controls("btnSaveTransaction2"), Object)
the direct cast isn't required as everything is an object and therefore the cast is always safe and going to succeed.

In the long run though it might be easier to have two separate methods - one to update the transactions table and one to update the transactions_weekly table and simply call the correct method(s) from the appropriate button click event.
 
Code refactoring

Generally, instead of using the same method to handle both clicks, I would suggest moving the shared code (code that would be executed by both handlers) to a seperate sub or function which is called by both handlers. Your Select block shows that there is quite a bit of button-specific code, so two handlers would make more sense. This would also allieviate your problem since the handlers would not need to check the sender parameter.

There are other ways you could refactor your code, such as putting the code for btnSaveTransaction2 into its own sub and calling it directly. Either way, I think some sort of refactoring would be the best solution, if only to make the code easier to understand.

As far as your current code goes:

  1. Dim objSender As Object = DirectCast(Me.Controls("btnSaveTransaction2"), Object)
    You never need to explicitly cast something to Object as all upcasts are implicit, and casting to Object is the ultimate upcast.
  2. I would suggest you use Me.controlname rather than Me.Controls("controlname") as this is more efficient, less prone to errors, and does not require a cast.
 
Back
Top