VB.NET 2.0:
我正在从VB.NET应用程序向SQL服务器发出备份命令。我正在捕获它发出的消息并将它们附加到多行文本框中。
但是,我要做的是允许应用程序继续响应GUI控件事件(主要是为了让用户可以调整输出窗口的大小或取消备份)。所以我使用BeginExecuteReader
并在Application.DoEvents()
的循环中旋转。但似乎只要备份开始发出其打印语句,我就会得到IAsyncResult.IsCompleted = True
并且它会下降到EndExecuteReader
,现在GUI再次被锁定。如何让它保持循环直到备份命令完成,但仍然获取那些输出语句并保持GUI响应?感谢。
这是我的代码:
' Enable retrieve print statements from the server'
AddHandler oConn.InfoMessage, AddressOf LogToBufferHandler
strSQL &= vbNewLine & "begin try"
strSQL &= vbNewLine & " declare @BackupName as varchar(255)"
strSQL &= vbNewLine & " declare @BackupDesc as varchar(255)"
strSQL &= vbNewLine & " declare @backupTime as varchar(50)"
strSQL &= vbNewLine & " set @backupTime = (select convert(datetime, getdate(), 100))"
strSQL &= vbNewLine & " set @BackupName = (SELECT '[' + db_name() + '] Full Backup')"
strSQL &= vbNewLine & " set @BackupDesc = (SELECT 'Automated full backup of [' + db_name() + '] on ' + @backupTime + '.')"
strSQL &= vbNewLine & " "
strSQL &= vbNewLine & " BACKUP DATABASE [#Database#]"
strSQL &= vbNewLine & " TO DISK = @BackupFullPath"
strSQL &= vbNewLine & " WITH stats,"
strSQL &= vbNewLine & " NAME = @BackupName,"
strSQL &= vbNewLine & " DESCRIPTION = @BackupDesc;"
strSQL &= vbNewLine & " select [IsSuccessful] = 1"
strSQL &= vbNewLine & " end try"
strSQL &= vbNewLine & " begin catch"
strSQL &= vbNewLine & " SELECT [IsSuccessful] = 0"
strSQL &= vbNewLine & " end catch"
'Workaround: Backup Database requires the name of the object, not a string'
' and I dont want to use dynamic SQL.'
strSQL = strSQL.Replace("#Database#", sb.InitialCatalog)
oConn.Open()
oCmd = New SqlCommand()
oCmd.Connection = oConn
oCmd.CommandText = strSQL
oCmd.CommandType = CommandType.Text
oCmd.Parameters.AddWithValue("@BackupFullPath", backupFullPath)
oCmd.CommandTimeout = 60 * 5
'Spin until complete, cancel, or timeout'
Dim result As IAsyncResult = oCmd.BeginExecuteReader(CommandBehavior.CloseConnection)
While Not result.IsCompleted
Application.DoEvents()
If blnCancel Then
oCmd.Cancel()
End If
System.Threading.Thread.Sleep(50)
End While
Try
oDataReader = oCmd.EndExecuteReader(result)
oDataTable.Load(oDataReader)
'Get results'
' (unfourtunately, you cannot do BeginExecuteScalar ASync in .Net 2.0,'
' so we are using a DataTable first column, row)'
If oDataTable IsNot Nothing _
AndAlso oDataTable.Rows.Count > 0 _
AndAlso oDataTable.Columns.Contains("IsSuccessful") _
AndAlso oDataTable.Rows(0).Item("IsSuccessful") = 1 Then
eBackupResult = BackupStatus.Succeeded
returnPath = backupFullPath 'Only set return path if the backup succeeded'
Else
eBackupResult = BackupStatus.Failed
End If
Catch ex As Exception
If Not ex.Message.Contains("cancelled by user") Then Throw ex
eBackupResult = BackupStatus.Canceled
End Try
答案 0 :(得分:1)
轮询循环(DoEvents
)被认为是邪恶的,原因有很多。这可能是您切换到BackgroundWorker
并放弃令人讨厌的Begin-poll-End方案的最简单方法。
如果你想保留它,这就是错误:接受读者可以很快但这并不意味着所有结果都已到达(让我说明一下:如果你查询了1TB的数据怎么办? - 读取的是一个漫长的过程)。您也需要以异步(轮询)方式Read
。现在事情变得无法控制。放弃它。
换句话说,oDataTable.Load
阻塞,很难解决。
答案 1 :(得分:0)
您可以使用TASKS。任务在概念上类似于线程。通过将代码放入任务中,主线程可以继续运行(这是获取用户输入并响应调整大小命令的线程)。
这篇文章更多地讨论了任务,并有一个VB.NET示例。
http://www.dotnetcurry.com/ShowArticle.aspx?ID=491
玩得开心!
答案 2 :(得分:0)
BackGroundWorker和ReportProgress