【问题标题】:VB.Net Allow A Certain Amount of Time To Complete A TaskVB.Net 允许一定的时间来完成一项任务
【发布时间】:2015-06-12 12:16:02
【问题描述】:

我正在尝试给我的程序一定的时间在远程驱动器发生故障之前建立连接,但我很难理解可用的不同选项。我已经尝试过计时器等,但程序仍然挂在正在联系数据库的部分。我已经研究并阅读到我需要运行后台工作程序,或者在另一个线程中运行它,但这超出了我目前的理解范围。

这是我目前所拥有的:

    Public Sub Initialise_View()
        Dim I As Integer = 0
        Dim Fault As Boolean = False
        Main.VIEW_SavingMessage.Visible = False

        Main.VIEW_Title.Text = "Establishing Connecion To Database... Please Wait"
        Main.Refresh()

        DataGridView_Setup.Set_Datasource(0) 'This subroutine opens a connection to
    'the database and will pass a fault variable back if the database is not found,
    'however this hangs for ages if the system is having trouble accessing the
    'network drive, upwards of 5mins sometimes!


        If Fault = True Then Main.VIEW_Title.Text = "Error In Connection..."
        Main.Refresh()

    End Sub

What I'd really like is something like:

    If Connection is not established within 30 seconds Then
         Msgbox "Error, Unable to establish connection"
         Exit Sub
    End If

Which would be easy, using a timer, as long as the program didn't hang when trying to actually connect.

So my question is, is there any way around this? If so, what's the best way of going about it?

TIA

**Update**

Following Answers, I have updated to the following:

Imports System.Threading

Module View_Initialise
    Public t1 As Threading.Thread
    Public Sub Initialise_View()
        Main.Timer1.Interval = 20 * 1000
        Main.Timer1.Start()

        t1 = New Thread(New ThreadStart(AddressOf Run_Datasource))
        t1.Start()

    End Sub

    Public Sub Run_Datasource()
        Dim I As Integer = 0
        Dim Fault As Boolean = False
        Main.VIEW_SavingMessage.Visible = False

        Main.VIEW_Title.Text = "Establishing Connecion To Database... Please Wait"
        Main.Refresh()

        DataGridView_Setup.Set_Datasource(0)
        DataGridView_Setup.BindingUpdates()

        If Fault = True Then Main.VIEW_Title.Text = "Error In Connection..."
        Main.Refresh()
    End Sub



End Module

这似乎有效,因为它确实触发了所有代码等,但Set_Datasource(0) 例程没有正确触发,在告诉用户窗体更新信息的部分代码中,这没有发生。这是来自Set_Datasource(0) 的代码:(对不起,太长了)

  Public Sub Set_Datasource(mode As Integer)

        Try
            Main.DataGridView1.DataSource.clear()
        Catch ex As Exception

        End Try

        Dim connString As String = My.Settings.Database_String
        Dim myConnection As OleDbConnection = New OleDbConnection
        myConnection.ConnectionString = connString
        ' create a data adapter 
        Dim da As OleDbDataAdapter = New OleDbDataAdapter("SELECT ID, [Name Of Person], [SAP Job Number], [Site Name], [Asset Description], [Spares Supplier], [Supplier Contact Name], [Supplier Contact Phone Number], [Supplier Contact Email], [Spares Description], [Part Number], [Quantity To Order], Cost, [Comments], [Request Date], [Date Ordered], [Ordered By], [Invoice Received], [Invoice Paid], [Method Of Payment], [Date Item Received], [Quote Attatchment] FROM Spares", myConnection)

        'create a new dataset 
        Dim ds As DataSet = New DataSet
        'fill DataSet

        Try
            da.Fill(ds, "Spares")
        Catch ex As Exception
            MsgBox("Sorry, An Error Occurred" & vbNewLine & _
                   "Database contents could not be loaded" & vbNewLine & vbNewLine & _
                   "Error Message: " & ex.Message, MsgBoxStyle.OkOnly, "Could Not Load Database Information")
            Exit Sub
        End Try


        Main.DataGridView1.DataSource = ds.Tables(0)

        Main.DataGridView1.AllowUserToAddRows = False

        'Set Site Listbox

        Dim SiteString = My.Settings.SETTINGS_SiteNames
        Dim SiteBox = Main.VIEW_Site.Items

        SiteBox.Clear()

        Do Until SiteString = ""
            Dim ActiveSiteName = Left(SiteString, InStr(SiteString, "¦"))
            ActiveSiteName = ActiveSiteName.Remove(ActiveSiteName.Length - 1)

            With SiteBox
                .Add(ActiveSiteName)
            End With

            SiteString = Replace(SiteString, ActiveSiteName + "¦", "")

        Loop


        'Set DataBindings
        Main.VIEW_Ref.DataBindings.Clear()
        Main.VIEW_Ref.DataBindings.Add(New Binding("Text", ds, "Spares.ID", False, DataSourceUpdateMode.Never))

        Main.VIEW_NameOfPerson.DataBindings.Clear()
        Main.VIEW_NameOfPerson.DataBindings.Add(New Binding("Text", ds, "Spares.Name Of Person", False, DataSourceUpdateMode.Never))

        Main.VIEW_SAPJobNo.DataBindings.Clear()
        Main.VIEW_SAPJobNo.DataBindings.Add(New Binding("Text", ds, "Spares.SAP Job Number", False, DataSourceUpdateMode.Never))

        Main.VIEW_Site.DataBindings.Clear()
        Main.VIEW_Site.DataBindings.Add(New Binding("Text", ds, "Spares.Site Name", False, DataSourceUpdateMode.Never))

        Main.VIEW_AssetDesc.DataBindings.Clear()
        Main.VIEW_AssetDesc.DataBindings.Add(New Binding("Text", ds, "Spares.Asset Description", False, DataSourceUpdateMode.Never))

        Main.VIEW_SparesSupplier.DataBindings.Clear()
        Main.VIEW_SparesSupplier.DataBindings.Add(New Binding("Text", ds, "Spares.Spares Supplier", False, DataSourceUpdateMode.Never))

        Main.VIEW_SupplierContactName.DataBindings.Clear()
        Main.VIEW_SupplierContactName.DataBindings.Add(New Binding("Text", ds, "Spares.Supplier Contact Name", False, DataSourceUpdateMode.Never))

        Main.VIEW_SupplierContactNumber.DataBindings.Clear()
        Main.VIEW_SupplierContactNumber.DataBindings.Add(New Binding("Text", ds, "Spares.Supplier Contact Phone Number", False, DataSourceUpdateMode.Never))

        Main.VIEW_SupplierContactNumber.DataBindings.Clear()
        Main.VIEW_SupplierContactNumber.DataBindings.Add(New Binding("Text", ds, "Spares.Supplier Contact Phone Number", False, DataSourceUpdateMode.Never))

        Main.VIEW_SupplierContactEmail.DataBindings.Clear()
        Main.VIEW_SupplierContactEmail.DataBindings.Add(New Binding("Text", ds, "Spares.Supplier Contact Email", False, DataSourceUpdateMode.Never))

        Main.VIEW_SparesDesc.DataBindings.Clear()
        Main.VIEW_SparesDesc.DataBindings.Add(New Binding("Text", ds, "Spares.Spares Description", False, DataSourceUpdateMode.Never))

        Main.VIEW_PartNumber.DataBindings.Clear()
        Main.VIEW_PartNumber.DataBindings.Add(New Binding("Text", ds, "Spares.Part Number", False, DataSourceUpdateMode.Never))

        Main.VIEW_QuantityToOrder.DataBindings.Clear()
        Main.VIEW_QuantityToOrder.DataBindings.Add(New Binding("Text", ds, "Spares.Quantity To Order", False, DataSourceUpdateMode.Never))

        Main.VIEW_CostEach.DataBindings.Clear()
        Main.VIEW_CostEach.DataBindings.Add(New Binding("Text", ds, "Spares.Cost", False, DataSourceUpdateMode.Never))

        Main.VIEW_DateRequested.DataBindings.Clear()
        Main.VIEW_DateRequested.DataBindings.Add(New Binding("Text", ds, "Spares.Request Date", False, DataSourceUpdateMode.Never))

        Main.VIEW_DateOrdered.DataBindings.Clear()
        Main.VIEW_DateOrdered.DataBindings.Add(New Binding("Text", ds, "Spares.Date Ordered", False, DataSourceUpdateMode.Never))

        Main.VIEW_OrderedBy.DataBindings.Clear()
        Main.VIEW_OrderedBy.DataBindings.Add(New Binding("Text", ds, "Spares.Ordered By", False, DataSourceUpdateMode.Never))

        Main.VIEW_InvoiceReceivedDate.DataBindings.Clear()
        Main.VIEW_InvoiceReceivedDate.DataBindings.Add(New Binding("Text", ds, "Spares.Invoice Received", False, DataSourceUpdateMode.Never))

        Main.VIEW_InvoicePaidDate.DataBindings.Clear()
        Main.VIEW_InvoicePaidDate.DataBindings.Add(New Binding("Text", ds, "Spares.Invoice Paid", False, DataSourceUpdateMode.Never))

        Main.View_MethodOfPayment.DataBindings.Clear()
        Main.View_MethodOfPayment.DataBindings.Add(New Binding("Text", ds, "Spares.Method Of Payment", False, DataSourceUpdateMode.Never))

        Main.VIEW_DateReceived.DataBindings.Clear()
        Main.VIEW_DateReceived.DataBindings.Add(New Binding("Text", ds, "Spares.Date Item Received", False, DataSourceUpdateMode.Never))

        Main.VIEW_AdditionalComments.DataBindings.Clear()
        Main.VIEW_AdditionalComments.DataBindings.Add(New Binding("Text", ds, "Spares.Comments", False, DataSourceUpdateMode.Never))

   DataGridView_Setup.BindingUpdates() 'CALL BELOW SUB HERE
        Main.VIEW_Title.Text = "View / Update Received Spares"
    End Sub

    Public Sub BindingUpdates()
        Dim curr As New DataGridViewRow
        curr = Main.DataGridView1.CurrentRow '**THIS LINE FAILS TO GET THE CURRENT ROW, HOWEVER, IF RUN WITHOUT A NEW THREAD, IT WORKS FINE??**




        Main.VIEW_Ref.Text = curr.Cells("ID").Value
        Main.VIEW_NameOfPerson.Text = curr.Cells("Name Of Person").Value
        Main.VIEW_SAPJobNo.Text = curr.Cells("SAP Job Number").Value
        Main.VIEW_Site.Text = curr.Cells("Site Name").Value
        Main.VIEW_AssetDesc.Text = curr.Cells("Asset Description").Value
        Main.VIEW_SparesSupplier.Text = curr.Cells("Spares Supplier").Value
        Main.VIEW_SupplierContactName.Text = curr.Cells("Supplier Contact Name").Value
        Main.VIEW_SupplierContactNumber.Text = curr.Cells("Supplier Contact Phone Number").Value
        Main.VIEW_SupplierContactEmail.Text = curr.Cells("Supplier Contact Email").Value
        Main.VIEW_SparesDesc.Text = curr.Cells("Spares Description").Value
        Main.VIEW_PartNumber.Text = curr.Cells("Part Number").Value
        Main.VIEW_QuantityToOrder.Text = curr.Cells("Quantity To Order").Value
        Main.VIEW_CostEach.Text = "£" + CStr(curr.Cells("Cost").Value)
        Main.VIEW_DateRequested.Text = curr.Cells("Request Date").Value


        'Handle DBNULL From now on

        If IsDBNull(curr.Cells("Date Ordered").Value) = True Or _
            IsNothing(curr.Cells("Date Ordered").Value) = True Or _
            curr.Cells("Date Ordered").Value = "" Or _
            curr.Cells("Date Ordered").Value = "Not Ordered Yet" Then

            With Main.VIEW_DateOrdered
                .Text = "Not Ordered Yet"
                .BackColor = Color.LightPink
            End With

        Else
            With Main.VIEW_DateOrdered
                .Text = curr.Cells("Date Ordered").Value
                .BackColor = Color.White
            End With

        End If

        If IsDBNull(curr.Cells("Ordered By").Value) = True Or _
            IsNothing(curr.Cells("Ordered By").Value) = True Or _
            curr.Cells("Ordered By").Value = "" Or _
            curr.Cells("Ordered By").Value = "Not Ordered Yet" Then
            With Main.VIEW_OrderedBy
                .Text = "Not Ordered Yet"
                .BackColor = Color.LightPink
            End With
        Else
            With Main.VIEW_OrderedBy
                .Text = curr.Cells("Ordered By").Value
                .BackColor = Color.White
            End With

        End If

        If IsDBNull(curr.Cells("Invoice Received").Value) = True Or _
            IsNothing(curr.Cells("Invoice Received").Value) = True Or _
            curr.Cells("Invoice Received").Value = "" Or _
            curr.Cells("Invoice Received").Value = "No Invoice" Then
            With Main.VIEW_InvoiceReceivedDate
                .Text = "No Invoice"
                .BackColor = Color.LightPink
            End With
        Else
            With Main.VIEW_InvoiceReceivedDate
                .Text = curr.Cells("Invoice Received").Value
                .BackColor = Color.White
            End With

        End If

        If IsDBNull(curr.Cells("Invoice Paid").Value) = True Or _
            IsNothing(curr.Cells("Invoice Paid").Value) = True Or _
            curr.Cells("Invoice Paid").Value = "" Or _
            curr.Cells("Invoice Paid").Value = "Not Paid" Then
            With Main.VIEW_InvoicePaidDate
                .Text = "Not Paid"
                .BackColor = Color.LightPink
            End With
        Else
            With Main.VIEW_InvoicePaidDate
                .Text = curr.Cells("Invoice Paid").Value
                .BackColor = Color.White
            End With

        End If

        If IsDBNull(curr.Cells("Method Of Payment").Value) = True Or _
            IsNothing(curr.Cells("Method Of Payment").Value) = True Or _
            curr.Cells("Method Of Payment").Value = "" Or _
            curr.Cells("Method Of Payment").Value = "Not Paid" Then
            With Main.View_MethodOfPayment
                .Text = "Not Paid"
                .BackColor = Color.LightPink
            End With
        Else
            With Main.View_MethodOfPayment
                .Text = curr.Cells("Method Of Payment").Value
                .BackColor = Color.White
            End With

        End If
        If IsDBNull(curr.Cells("Date Item Received").Value) = True Or _
            IsNothing(curr.Cells("Date Item Received").Value) = True Or _
            curr.Cells("Date Item Received").Value = "" Or _
            curr.Cells("Date Item Received").Value = "Not Received" Then
            With Main.VIEW_DateReceived
                .Text = "Not Received"
                .BackColor = Color.LightPink
            End With
        Else
            With Main.VIEW_DateReceived
                .Text = curr.Cells("Date Item Received").Value
                .BackColor = Color.White
            End With

        End If

        If IsDBNull(curr.Cells("Comments").Value) = True Or _
            IsNothing(curr.Cells("Comments").Value) = True Or _
            curr.Cells("Comments").Value = "" Or _
            curr.Cells("Comments").Value = "No Comments Added" Then
            With Main.VIEW_AdditionalComments
                .Text = "No Comments Added"
                '.BackColor = Color.LightPink
            End With
        Else
            With Main.VIEW_AdditionalComments
                .Text = curr.Cells("Comments").Value
                '.BackColor = Color.White
            End With

        End If



    End Sub

End Module

如上代码所述,错误似乎是新线程无法访问表单中的信息?

谢谢。

【问题讨论】:

    标签: vb.net multithreading timer backgroundworker


    【解决方案1】:

    您需要将连接子例程作为新线程运行。 Thread 的一个常见示例如下:

    首先创建你的新线程:

    Public t1 As Threading.Thread
    

    现在从你的函数调用线程

    Private Sub Initialise_View()
        'Run your connecting Sub-Routine
        t1 = New Thread(New ThreadStart(AddressOf Set_Datasource))
        t1.Start()
    End sub
    

    现在你的连接子例程

    Sub Set_Datasource()
        'Your code here
    End sub 
    

    现在您的应用不会挂断。

    同时你可以启动一个定时器,让它在 30 秒后关闭连接,现在是线程,然后显示你的错误。

    【讨论】:

    • 嗯,这似乎是在尝试触发代码,但是当 Set_datasource 子运行时,它现在不会更新表单。我将更新我的问题以显示
    【解决方案2】:

    我需要运行一个后台工作程序,或者在另一个线程中运行它,但这超出了我目前的理解。

    实际上,BackgroundWorkers 非常简单,只要您正确理解了这个概念。它们实际上只是第二个线程,封装在一个开箱即用的优化类中,已经包含了完成任务所需的方法,而不会冻结主线程。

    一个我用过很多次的简单实现如下所示:

    Imports System.ComponentModel
    
    Public Class BGWexample
        Sub MainProgram()
            '   delcare your bgWoker-object
            Dim BgWorker As BackgroundWorker
    
            '   initialization and basic setup of your bgWorker
            BgWorker = New BackgroundWorker()
            BgWorker.WorkerReportsProgress = False
            BgWorker.WorkerSupportsCancellation = False
    
            '   tell the bgWorker where it will find the code for it's already implemented methods
            AddHandler BgWorker.DoWork, AddressOf BgWorkerDoesHisThing
            AddHandler BgWorker.RunWorkerCompleted, AddressOf BgWorkerHasFinished
    
            '   to start your background thread, just execute the bgWoker by calling its .RunWorkerAsync-method instead of calling your already implemented method to load your data from the database
            BgWorker.RunWorkerAsync()
        End Sub
    
        Private Sub BgWorkerDoesHisThing(ByVal sender As Object, ByVal e As DoWorkEventArgs)
            '   this will host the code to load the data from the database, e.g. declaration of your Data-Access-Object, querying, populating DataTables etc.
        End Sub
    
        Private Sub BgWorkerHasFinished(ByVal sender As Object, ByVal e As RunWorkerCompletedEventArgs)
            '   use this method to hide any loading screens, enable some controls etc.
        End Sub
    End Class
    

    只需将Set_Datasource(mode As Integer) 的代码放在BgWorkerDoesHisThing() 方法中,然后执行BgWorker.RunWorkerAsync() 方法而不是Set_Datasource(mode As Integer) 方法。

    这将导致 BgWorker 执行 BgWorkerDoesHisThing()-Sub,它通过在声明块中添加相应的 Handler 附加到 .DoWork-Event。

    请注意:如果要从后台线程与 GUI 交互,使用后台线程会有点麻烦。

    在本例中,BgWorkerDoesHisThing()-Sub 作为不同的线程执行,不允许修改主线程的 GUI-controls,而BgWorkerHasFinished()-Sub 将在主线程中执行再次,这意味着它再次拥有对 GUI 控件的完全访问权限。

    所以现在,我建议将您的 GUI 放入加载屏幕,并在 BgWorkerHasFinished()-method 中隐藏该加载屏幕。

    请记住,如果您的主线程取决于后台线程的结果,但不等待它完成工作,您可能会遇到Race Hazard。这就是BackgroundWorker.RunWorkerCompleted-event 的用途,这也是我向该事件添加 EventHandler 的原因,它会在 BgWorker 完成工作后立即执行专用的 BgWorkerHasFinished()-method。

    【讨论】:

    • 我在某种程度上得到了这个答案。我已经设法让后台工作人员填充数据集,但是在更新主要表单项时,系统由于问题中描述的相同问题而崩溃。 `curr = Main.DataGridView1.CurrentRow` 失败,因为在 Datagrid 中找不到当前行(因为后台工作人员不会填充 datagrid)。因此,我尝试填充公共数据集,然后将 Datagrid 填充回主表单代码中,但这仍然因同样的问题而失败。有什么想法吗?
    • 由于您的 BackgroundWorker 使用了除 GUI 控件之外的其他线程,因此不允许直接与 GUI 交互。由于 BGW 线程无法确定 GUI 对象在特定时间将具有哪种状态,因此这些调用将非常不稳定。这是因为 BGW-Thread 与主 (GUI) 线程异步运行。要与 GUI 交互,请使用 GUI Dispatcher.Invoke()-method。
    • 您是否确保您的 DataGridView 已正确填充行之后执行 curr = Main.DataGridView1.CurrentRow?为此,请将所有需要运行的代码从数据库中获取数据(例如在 DataGridView 中显示并访问某个 DataRow)放在BgWorkerHasFinished()-方法中。您的代码结构应如下所示:BgWorkerDoesHisThing() --> 从数据库中提取数据。 BgWorkerHasFinished() --> 填充 DataGridView;访问某一行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-08
    • 1970-01-01
    • 1970-01-01
    • 2013-01-04
    • 1970-01-01
    • 2022-01-15
    相关资源
    最近更新 更多