Home > other >  Freeze UI with Threads
Freeze UI with Threads

Time:11-10

I have a timer to make a thread:

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    'ListBox2.Items.Add("Hilo")
    hiloCertificador1 = New Thread(AddressOf crearObjeto1)
    hiloCertificador1.IsBackground = True
    hiloCertificador1.Start()
End Sub
Public Sub crearObjeto1()
    UpdateList()
End Sub
Private Delegate Sub UpdateListDelegate()
Private Sub UpdateList()
    If Me.InvokeRequired Then
        Me.BeginInvoke(New UpdateListDelegate(AddressOf UpdateList))
    Else
        Dim conn As New SqlConnection(parametrosCon)
        Dim cmd = New SqlCommand("SELECT TOP 1 * FROM COLA WHERE docentry < 8654 and enviado = 0", conn)
        Dim da As New SqlClient.SqlDataAdapter(cmd)
        cmd.Connection.Open()
        da.SelectCommand = cmd
        da.Fill(dataSet, "Query")
        For Each fila As DataRow In dataSet.Tables(0).Rows
            cmd = New SqlCommand("UPDATE COLA SET enviado = 1 WHERE DOCENTRY = (@docEntry)  AND TIPO = (@tipodoc)", conn)
            cmd.Parameters.AddWithValue("@docEntry", fila("docentry"))
            cmd.Parameters.AddWithValue("@tipodoc", fila("tipo"))
            cmd.ExecuteNonQuery()
            Dim factura As New FacturaCerificacion(fila("docentry"), fila("tipo"))
        Next
        cmd.Connection.Close()
        dataSet.Tables("Query").Clear()
    End If
End Sub

The timer have a 4000 interval, but when a thread start freeze my UI, I think is because the process is so big or the querys but i need make it without freezing.

CodePudding user response:

The comment is correct, and I will describe for you the issues hinted therein

Using a System.Windows.Forms.Timer

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick

This will run on the UI thread, and is only appropriate when doing UI things (even then, I am not sure you can really make a case for it over System.Threading.Timer)

Creating a new System.Threading.Thread

hiloCertificador1 = New Thread(AddressOf crearObjeto1)
hiloCertificador1.IsBackground = True
hiloCertificador1.Start()

This now runs off the UI, and is the entire contents of the Timer.Tick. So you've ticked on the UI then created a new thread off the UI. This is very odd

Calling a Sub to call a Sub

Public Sub crearObjeto1()
    UpdateList()
End Sub
Private Sub UpdateList()
    ' do stuff
End Sub

The redundancy should be self-evident

Doing non-UI stuff but following the Control.InvokeRequired/BeginInvoke pattern

Private Delegate Sub UpdateListDelegate()
Private Sub UpdateList()
    If Me.InvokeRequired Then
        Me.BeginInvoke(New UpdateListDelegate(AddressOf UpdateList))
    Else
        ' looks like a bunch of non-UI stuff
    End If
End Sub

This pattern is used for doing things on the UI but there seems to be no UI code in that block.

Not using Using to ensure proper disposal of IDisposable objects

Dim conn As New SqlConnection(parametrosCon)
Dim cmd = New SqlCommand("SELECT TOP 1 * FROM COLA WHERE docentry < 8654 and enviado = 0", conn)
Dim da As New SqlClient.SqlDataAdapter(cmd)
' do stuff
cmd.Connection.Close()
DataSet.Tables("Query").Clear()

Nongermane to your current issue, but also important to know.

Solution

So although it looks like a noble effort, you seem to be going back and forth between UI and not for no reason at all, or more accurately, creating issues where none existed with some over-engineering. The whole thing can be simplified with some minor changes

Use System.Threading.Timer

Dim Timer2 As New System.Threading.Timer(Sub() UpdateList(), Nothing, -1, -1)

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ' done in Form_Load if your Timer1 is Enabled in designer
    ' or can be done in a Button.Click, or however you had enabled Timer1
    Timer2.Change(2000, 4000) ' this will enable Timer after 2 seconds, then will tick every 4 seconds
    'Timer2.Change(-1, -1) ' this is how it's disabled
End Sub

Just call this method, and use Using to properly dispose your database objects. Added a Sub DoUiStuff() which is how the pattern is properly implemented

Private Sub UpdateList()
    Timer2.Change(-1, -1)
    Using conn As New SqlConnection(parametrosCon)
        conn.Open()
        Using cmd = New SqlCommand("SELECT TOP 1 * FROM COLA WHERE docentry < 8654 and enviado = 0", conn)
            Using da As New SqlClient.SqlDataAdapter(cmd)
                da.SelectCommand = cmd
                da.Fill(DataSet, "Query")
                For Each fila As DataRow In DataSet.Tables(0).Rows
                    Using cmdInner = New SqlCommand("UPDATE COLA SET enviado = 1 WHERE DOCENTRY = (@docEntry)  AND TIPO = (@tipodoc)", conn)
                        cmd.Connection.Open()
                        cmd.Parameters.AddWithValue("@docEntry", fila("docentry"))
                        cmd.Parameters.AddWithValue("@tipodoc", fila("tipo"))
                        cmd.ExecuteNonQuery()
                        Dim factura As New FacturaCerificacion(fila("docentry"), fila("tipo"))
                    End Using
                Next
            End Using
        End Using
        DoUiStuff(arguments) ' for example, if you need to update a GridView
        DataSet.Tables("Query").Clear()
    End Using
End Sub

Private Sub DoUiStuff(arguments As Whatever)
    If Me.InvokeRequired() Then
        Me.Invoke(New Action(Of Whatever)(AddressOf DoUiStuff), arguments)
    Else
        ' do UI stuff with arguments
    End If
    Timer2.Change(2000, -1)
End Sub

Finally, so I'm not contradicting myself, I'll add the Dispose method to dispose of the Timer. This Sub will be by default in your Form.Designer.vb file which you can leave there or move it to Form.vb once you add to it.

'Form overrides dispose to clean up the component list.
<System.Diagnostics.DebuggerNonUserCode()>
Protected Overrides Sub Dispose(ByVal disposing As Boolean)
    Try
        If disposing Then
            components?.Dispose()
            Timer2?.Dispose()
        End If
    Finally
        MyBase.Dispose(disposing)
    End Try
End Sub
  • Related