locked
Program Based Events Versus User Initiated Events RRS feed

  • Question

  • I have three controls on a form, a DataGridView, a ListBox, and a ComboBox.  The data for populating the three controls are contained in three related tables Agent, Client, and Itinerary in MySQL database.  When the form is activated under program control I wish to populate all three tables before the User sees the form.  Once the form is displayed, the user has the option to select a different Agent in the DataGridView which will cascade changes to the Client list in the ListBox and the Itinerary list in the ComboBox.  I'm using a MyBase.Load event to initially populate the Agents in DataGridView and Functions to initially populate the other controls (Client & Itinerary).  This part works well.  When I add subroutines to handle changes to the Agent or Client controls, I get into trouble.  Stepping through the code indicates that just populating the DataGridView control triggers the subroutine that handles the DataGridView SelectionChanged event which causes redundant function calls.  Similarly,  just populating the ListBox triggers the subroutine that handles the ListBox.SelectedValueChange again resulting in redundant function calls.  My question: Is there a way to handle Program induced  events separately from User induced events?  I've attached the code.

    Imports MySql.Data.MySqlClient
    Public Class Form2
        Public clientid As Integer
        Private Sub Create_Itinerary_Load() Handles MyBase.Load
            '------------------------------------------------------------------------------
            'Fill Agent List DataGridView with results from a MySQL query.
            '------------------------------------------------------------------------------
            Dim con As MySqlConnection = New MySqlConnection("Data Source=localhost;Database=fit;User ID=alan;Password=alan1939;")
            Dim ds As DataSet = New DataSet
            Dim DataAdapter1 As MySqlDataAdapter = New MySqlDataAdapter()
            Dim datagrid1 As New DataGridView
            con.Open()
            DataAdapter1.SelectCommand = New MySqlCommand("SELECT agt_nid, agt_first_name 'First Name', agt_last_name 'Last Name', agt_company_name 'Agency Name' FROM agent", con)
            DataAdapter1.Fill(ds, "Agent")
            If ds.Tables(0).Rows.Count = 0 Then
                Exit Sub
            Else
                DataGridView1.DataSource = ds
                DataGridView1.DataMember = "Agent"
                DataGridView1.Columns("agt_nid").Visible = False
                DataGridView1.Rows(0).Cells(1).Selected = True
                DataGridView1.ReadOnly = True
                con.Close()
            End If
        End Sub
        Private Sub display_clients() Handles DataGridView1.SelectionChanged
            get_clients(DataGridView1.CurrentRow.Cells("agt_nid").Value)
        End Sub
        'Private Sub display_itinerary() Handles ListBox1.SelectedValueChanged
        '    get_itinerary(ListBox1.SelectedValue)
        'End Sub
        Function get_clients(ByVal agentid As Integer)
            '-----------------------------------------------------------------
            'Fill Client ListBox using Selected Value from Agent DataGridView.
            '-----------------------------------------------------------------        
            Dim con3 As New MySqlConnection
            Dim constr3 As String = "Data Source=localhost;Database=fit;User ID=alan;Password=alan1939;"
            con3.ConnectionString = constr3
            con3.Open()
            'Create SELECT statement to get associated clients using previously selected agent's id
            Dim SelStmt As String = "SELECT clt_nid, CONCAT(clt_title, + ' ', + clt_first_name, ' ', clt_last_name) 'Client Name' " _
                & "FROM agent, agt2clt, client " _
                & "WHERE agt_nid=a2c_agt_nid AND a2c_clt_nid = clt_nid AND agt_nid =" _
                & agentid.ToString + ";"
            'Create SQL command to connect to and query MySQL database
            Dim cmd As New MySqlCommand(SelStmt, con3)
            'Create data table and create and fill data adapter
            Dim da As MySqlDataAdapter = New MySqlDataAdapter(cmd)
            Dim dt As New DataTable("Client Name")
            da.Fill(dt)
            If dt.Rows.Count() = 0 Then
                ListBox1.DataSource() = Nothing
                Exit Function
            Else
                ListBox1.DataSource = dt
                ListBox1.DisplayMember = "Client Name"
                ListBox1.ValueMember = "clt_nid"
                get_itinerary(ListBox1.SelectedValue)
            End If
        End Function
        'Create MySQL database connection and connection string
        Function get_itinerary(ByVal clientid As Integer)
            '------------------------------------------------------------------
            'Fill  Itinerary ComboBox using Selected Value from Client ListBox.
            '------------------------------------------------------------------
            ComboBox5.ResetText()
            Dim con2 As New MySqlConnection
            Dim constr2 As New String("Data Source=localhost;Database=fit;User ID=alan;Password=alan1939;")
            Try
                con2.ConnectionString = constr2
                con2.Open()
                'Create SELECT statement to get associated itineraries using selected client's id
                Dim SelStmt2 As New String("SELECT DISTINCT itn_nid, itn_name, itn_create_date, itn_last_changed_date " _
                    & "FROM client, clt2itn, itinerary WHERE clt_nid = c2i_clt_nid AND  " _
                    & "c2i_itn_nid = itn_nid AND clt_nid = " & clientid.ToString & " ORDER BY itn_name;")
                Dim cmd2 As New MySqlCommand(SelStmt2, con2)
                Dim da2 As MySqlDataAdapter = New MySqlDataAdapter(cmd2)
                Dim dt2 As New DataTable("Itinerary Name")
                da2.Fill(dt2)
                If dt2.Rows.Count() = 0 Then
                    Exit Function
                Else
                    ComboBox5.DataSource = dt2
                    ComboBox5.DisplayMember = "itn_name"
                    ComboBox5.ValueMember = "itn_nid"
                    'TextBox2.DataBindings.Add("Text", dt2, "itn_create_date")
                    'TextBox3.DataBindings.Add("text", dt2, "itn_last_changed_date")
                End If
            Catch ex As MySqlException
                MsgBox(ex.Message)
            Finally
                con2.Close()
            End Try
        End Function
        'End Sub
    End Class

    Wednesday, July 18, 2012 8:23 PM

Answers

All replies

  • The first action after installing VB should be setting Option Strict On as the default value in the IDE options. For already created projects you can enable it in the project properties, or on a per-file basis by putting "Option Strict On" at the top of a code file. With Option Strict Off, your code may fail because you've activated unsafe programming, disabled compiler checks and enabled the automatic and unattended generation of implicit conversions that may fail or not, or may give unexpected or undesirable results. In addition, it enables late-binding which is slow at run-time and steals the ability of verifying the existence of type members from the compiler. It is often hard for people trying to help if the code is not compilable and errors have to be fixed first. Data type awareness and correct data type handling are most essential for every programmer.

    Armin

    Wednesday, July 18, 2012 8:28 PM
  • I have found the answer to my question, "Is there a way to handle Program induced events separately from User induced events?", and the answer is Yes, but it is an ugly workaround.  This is true for the DataGridView and the ListBox controls.  However, Microsoft has provided a more elegant solution for the ComboBox control which can be found at http://msdn.microsoft.com/en-us/library/system.windows.form.combobox.selectionchangecommitted.aspx.

    One wonders why all controls don't have a similar feature??  In any case, the workaround can be found at http://stackoverflow/questions/3150882/how-to-prevent-value-changed-events-from-firing-on-form-initialization-in-vb-net.

    • Marked as answer by one4all1939 Wednesday, July 25, 2012 2:54 PM
    Thursday, July 19, 2012 10:03 PM
  • The 'hack' is pretty much the best, most versatile and reliable, way of handling this situation. That is, at the end of the initialization routine, set your Initialized flag True. In each event handler, check the Initialized flag: if it is False then exit the handler.

    The SelectionChangeCommitted is made available because of the way the underlying operating system combobox works (and, apparently, doesn't work all the time). It would be nice to have a reliable mechanism from differentiating user and programmatic event calls. Perhaps it's a lot harder than one thinks? I don't know, but that win32 stuff can be very ugly.


    Stephen J Whiteley

    Friday, July 20, 2012 8:44 PM