0

我正在开发一个 Winform 程序,用户可以在其中下载大型 blob 文件。为了可视化进度,我在表单上添加了一个进度条。下载 blob 工作正常,但我不知道如何在下载过程中更新进度条。

这是我目前所拥有的......

        Private Sub frmMeldingNieuweVersie_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        
        ProgressBar1.Minimum=0
        ProgressBar1.Maximum=100
        ProgressBar1.Value=10
        BackgroundWorker1.RunWorkerAsync()
    
        
    End Sub
    
    Private Sub BackgroundWorker1_DoWork(ByVal sender As System.Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
            Dim objReader As MySqlDataReader
            Dim connectionString As String = ConfigurationManager.ConnectionStrings("MySqlConnectionString").ToString()
            dim filename As String = "setup.exe"
            dim setupFile As String
            Dim strLatestVersion As String
            Dim bytesLoad As Byte()
    
            Try
                myCmd.Connection = myConnection.Open
                myCmd.CommandText = "SELECT setupFile, OCTET_LENGTH(SetupFile) AS FileSize FROM Versiebeheer ORDER BY Versienummer DESC LIMIT 1"
                objReader = myCmd.ExecuteReader
    
                While objReader.Read
                    'BackgroundWorker1.ReportProgress(e.percentProgress)
                    If objReader.HasRows Then
    
                        strLatestVersion = Replace(objReader("Versienummer"),".","")
    
                            If Not IsDBNull(objreader("setupFile")) then
                                bytesLoad = DirectCast(objReader("setupFile"), Byte())
                                setupFile = "C:\Temp\" & filename
                            End If
                        objReader.Close()
                        objReader = Nothing
                    End If
    
                End While
                
                myConnection.Close()
            Catch ex As Exception
                MessageBox.Show(ex.Message)
                myConnection.Close()
            End Try
        End Sub

Private Sub BackgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
        Invoke(Sub()
            Me.ProgressBar1.Value = 50'e.ProgressPercentage
        End Sub)
    End Sub

    Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
        'Close()
    End Sub

是否可以为此问题制作进度条,还是我做错了什么?

4

2 回答 2

0

我找到了解决我的问题的方法。这是进度条的工作代码。backgroundworker 没有工作的原因是因为 WorkerReportsProgress 设置为 False。

    Private Sub frmMeldingNieuweVersie_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    ProgressBar1.Minimum = 0
    ProgressBar1.Maximum = 100

    BackgroundWorker1.RunWorkerAsync()

End Sub
Private Sub backgroundWorker1_DoWork(ByVal sender As Object, ByVal e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
    ' Get the BackgroundWorker object that raised this event.
    Dim worker As BackgroundWorker =
            CType(sender, BackgroundWorker)
    e.Result = RetrieveFile(worker, e)
End Sub
Private Function RetrieveFile(ByVal worker As BackgroundWorker, ByVal e As DoWorkEventArgs) As Byte()
    Dim objReader As MySqlDataReader
    Dim connectionString As String = ConfigurationManager.ConnectionStrings("MySqlConnectionString").ToString()

    Try
        myCmd.Connection = myConnection.Open
        myCmd.CommandText = "SELECT OCTET_LENGTH(SetupFile) AS fileSize, setupFile FROM Versiebeheer ORDER BY Versienummer DESC LIMIT 1"
        objReader = myCmd.ExecuteReader(CommandBehavior.SequentialAccess)

        While objReader.Read

            If objReader.HasRows Then

                Dim memory As New MemoryStream
                Dim startIndex As Long = 0
                Const ChunkSize As Integer = 256
                Dim totalSize As Long = objReader("fileSize")
                Dim progressPercentage As Integer

                Do
                    Dim buffer(ChunkSize - 1) As Byte

                    Dim retrievedBytes As Long = objReader.GetBytes(1, startIndex, buffer, 0, ChunkSize)

                    memory.Write(buffer, 0, CInt(retrievedBytes))

                    startIndex += retrievedBytes

                    progressPercentage = (startIndex / totalSize) * 100
                    worker.ReportProgress(progressPercentage)
                    lblPercentage.Invoke(New SetValueDelegate(AddressOf SetValue), New Object() {progressPercentage})

                    If retrievedBytes <> ChunkSize Then

                        Exit Do
                    End If
                Loop

                myCmd.Connection.Close()

                Dim data() As Byte = memory.ToArray()

                memory.Dispose()
                Return data

            End If

        End While


        myConnection.Close()
    Catch ex As Exception
        MessageBox.Show(ex.Message)
        myConnection.Close()
    End Try
End Function

Private Sub backgroundWorker1_ProgressChanged(ByVal sender As Object, ByVal e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged

    Me.ProgressBar1.Value = e.ProgressPercentage

End Sub

Public Delegate Sub SetValueDelegate(ByVal value As Integer)

Public Sub SetValue(ByVal value As Integer)
    lblPercentage.Text = value.ToString() & "%"
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
    Dim bytesLoad As Byte()
    Dim worker As BackgroundWorker =
            CType(sender, BackgroundWorker)
    ProgressBar1.Minimum = 0
    ProgressBar1.Maximum = 100

    Dim filename As String = "C:\tmp\setup.exe"
    bytesLoad = e.Result
    Using fs As New FileStream(filename, FileMode.OpenOrCreate, FileAccess.Write)
        fs.Write(bytesLoad, 0, bytesLoad.Length)
        'Set image variable value using memory stream. 
        fs.Flush()
        fs.Close()
        btnInstalleerUpdate.Enabled = True
    End Using
End Sub
于 2021-03-05T07:50:25.660 回答
0

问题是,大部分处理不是在 中While objReader.Read,而是在objReader = myCmd.ExecuteReader.

在执行 SQL 时,您的工作线程正在等待。它没有时间报告进度。

我看到了几种解决这个问题的方法

  • 主线程启动一个System.Timers.Timer. 这是最简单的定时器。每当计时器过去时,将 ProgressBar 前进一步
  • 主线程启动一个额外的 BackgroundWorker,它将每秒左右报告(假)进度。一步一步更新 ProgressBar

问题是,只要您真的不知道查询需要多长时间,进度条中的值并不能真正显示进度。

我不熟悉获取 blob。是否可以在子块中获取数据?如果是这样,每个获取的 subBlob 都会报告为进度。如果您从计算预期的子 blob 数量开始,则可以计算实际进度。

幸运的是,Bjorn M 展示了如何将 blob 分成几块!

我将他的解决方案编辑到这个答案中以增强格式

谢谢比约恩!

我的 VB 有点生疏,所以我先展示 C# 中的代码,然后展示 Bjorns 格式的代码

const string sqlText = "SELECT OCTET_LENGTH(SetupFile) AS fileSize,"
   + " setupFile FROM Versiebeheer"
   + " ORDER BY Versienummer DESC"
   + " LIMIT 1";
using (var dbConnection = new DbConnection(connectionString))
{
    using (var dbCommand = dbConnection.CreateCommand())
    {
        dbCommand..CommandText = sqlText;
        dbCommand.Parameters.AddWithValue("@Username", txtLoginnaam.Text);
        dbConnection.OPen();

        var dbReader = myCmd.ExecuteReader(commandbehavior.SequentialAccess);
        while (dbReader.Read())
        {
            // still something to read
            var readData = ... // use DbReader to fill the read data

            // process the read data and notify about progress:
            ProcessReadData(readData); 
        }
    }
}

或类似 VB 的格式

myCmd.Connection = myConnection.Open
myCmd.CommandText = "SELECT OCTET_LENGTH(SetupFile) AS fileSize, setupFile FROM Versiebeheer ORDER BY Versienummer DESC LIMIT 1"
myCmd.Parameters.AddWithValue("@Username", txtLoginnaam.Text)            
objReader = myCmd.ExecuteReader(commandbehavior.SequentialAccess)

Do
    Dim buffer(ChunkSize - 1) As Byte
    Dim retrievedBytes As Long = 
        objReader.GetBytes(1, startIndex, buffer, 0, ChunkSize)                                                  
    memory.Write(buffer, 0, CInt(retrievedBytes))                        
    startIndex += retrievedBytes
    If retrievedBytes <> ChunkSize Then                              
       progressPercentage = (startIndex/totalSize)*100                           
       this.ReportProgress(progressPercentage)                                                   
Exit Do

Bjorn 的注意事项:此代码将由 BackgroundWorker 执行。BackGroundWorker 不知道是谁启动的,因此不应访问 ProgressBar。

启动 BackGroundWorker 的表单从 BackGroundWorkder 订阅 ProgressReported 事件。在事件处理程序中,progressPercentage 由 UI 线程读取,该线程可以相应地更新 ProgressBar。

于 2021-03-04T10:36:48.600 回答