我有一个程序来构建报告文档,我想放置 例行程序根据" DoWork"后台工作者的处理程序。报告的初始部分已启动,但是,一旦我在组合框中引用所选项目,它就会停止执行吗?
这是我的代码:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
ProgressBar1.Visible = True
Application.EnableVisualStyles()
ProgressBar1.Style = ProgressBarStyle.Marquee
ProgressBar1.MarqueeAnimationSpeed = 10
Dim x As New Thread(AddressOf buildReport)
x.Start()
MessageBox.Show("Build Complete")
ProgressBar1.Visible = False
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
'builds the report
Public Sub buildReport()
Dim app As word.Application = New word.Application
Dim document As word.Document
Dim today As String()
app.Visible = True
document = app.Documents.Add("K:\ETL Test Files\" & mycallerPreview.previewInst.txtYear.Text & "\" & mycallerPreview.previewInst.txtVendor.Text & "\" & mycallerPreview.previewInst.txtReport.Text & "\Test Report\Report Data\ReportTemplate.doc") 'open up template
'document.Styles.Add("Contents1")
'document.Styles.Add("Contents2")
'document.Styles.Add("Contents3")
'add info to pre-made bookmarks
today = Date.Today.ToString.Split(" ")
document.Bookmarks("Date").Range.Text = today(0).ToString
document.Bookmarks("Date1").Range.Text = today(0).ToString
document.Bookmarks("Date2").Range.Text = today(0).ToString
document.Bookmarks("Date3").Range.Text = today(0).ToString
document.Bookmarks("Approver").Range.Text = mycallerPreview.mycallerSelect2.txtChecked.Text.ToString
document.Bookmarks("Number2").Range.Text = mycallerPreview.mycallerSelect2.txtReportNumber.Text.ToString
document.Bookmarks("Number1").Range.Text = mycallerPreview.mycallerSelect2.txtReportNumber.Text.ToString
document.Bookmarks("Vendor").Range.Text = mycallerPreview.previewInst.txtVendor.Text.ToString
document.Bookmarks("Test1").Range.Text = mycallerPreview.mycallerSelect2.txtReportTitle.Text.ToString
document.Bookmarks("TestTitle").Range.Text = mycallerPreview.mycallerSelect2.txtReportTitle.Text.ToString
If mycallerPreview.mycallerSelect2.cmbName.SelectedIndex <> -1 Then
document.Bookmarks("Writer").Range.Text = mycallerPreview.mycallerSelect2.cmbName.SelectedItem.ToString
document.Bookmarks("Reviewer").Range.Text = mycallerPreview.mycallerSelect2.cmbName.SelectedItem.ToString
End If
If mycallerPreview.mycallerSelect2.cmbQuote.SelectedIndex <> -1 Then
document.Bookmarks("Quote").Range.Text = mycallerPreview.mycallerSelect2.cmbQuote.SelectedItem.ToString
End If
我的word文档中的所有书签都会被填写,直到它到达位于&#34; DoWork&#34;底部的组合框引用。处理程序。有什么建议吗?
正如所建议的那样,我尝试了线程同步......
Dim x As New Thread(AddressOf buildReport)
x.Start()
这并没有解决我的问题,但给了我以下例外:
跨线程操作无效:控制&#39; cmbName&#39;从创建它的线程以外的线程访问。
修:
'garbage collects and initializes progress bar to default values
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
'create list of objects to pass through ThreadStart Method
Dim list As New List(Of Object)
If mycallerPreview.mycallerSelect2.cmbName.SelectedIndex <> -1 Then
list.Add(mycallerPreview.mycallerSelect2.cmbName.SelectedItem.ToString)
End If
If mycallerPreview.mycallerSelect2.cmbQuote.SelectedIndex <> -1 Then
list.Add(mycallerPreview.mycallerSelect2.cmbQuote.SelectedItem.ToString)
End If
list.Add(ProgressBar1)
Dim x As New Thread(AddressOf buildReport)
x.Start(list)
MessageBox.Show("Build Complete")
GC.Collect()
GC.WaitForPendingFinalizers()
GC.Collect()
GC.WaitForPendingFinalizers()
End Sub
'builds the report
Public Sub buildReport(list_temp As Object)
Dim progress As New ProgressBar
progress = list_temp(2)
progress.Visible = True
Application.EnableVisualStyles()
progress.Style = ProgressBarStyle.Marquee
progress.MarqueeAnimationSpeed = 10
Dim list As List(Of Object) = list_temp
Dim app As word.Application = New word.Application
Dim document As word.Document
Dim today As String()
app.Visible = True
document = app.Documents.Add("K:\ETL Test Files\" & mycallerPreview.previewInst.txtYear.Text & "\" & mycallerPreview.previewInst.txtVendor.Text & "\" & mycallerPreview.previewInst.txtReport.Text & "\Test Report\Report Data\ReportTemplate.doc") 'open up template
'add info to pre-made bookmarks
today = Date.Today.ToString.Split(" ")
document.Bookmarks("Date").Range.Text = today(0).ToString
document.Bookmarks("Date1").Range.Text = today(0).ToString
document.Bookmarks("Date2").Range.Text = today(0).ToString
document.Bookmarks("Date3").Range.Text = today(0).ToString
document.Bookmarks("Approver").Range.Text = mycallerPreview.mycallerSelect2.txtChecked.Text.ToString
document.Bookmarks("Number2").Range.Text = mycallerPreview.mycallerSelect2.txtReportNumber.Text.ToString
document.Bookmarks("Number1").Range.Text = mycallerPreview.mycallerSelect2.txtReportNumber.Text.ToString
document.Bookmarks("Vendor").Range.Text = mycallerPreview.previewInst.txtVendor.Text.ToString
document.Bookmarks("Test1").Range.Text = mycallerPreview.mycallerSelect2.txtReportTitle.Text.ToString
document.Bookmarks("TestTitle").Range.Text = mycallerPreview.mycallerSelect2.txtReportTitle.Text.ToString
document.Bookmarks("Writer").Range.Text = list(0).ToString
document.Bookmarks("Reviewer").Range.Text = list(0).ToString
document.Bookmarks("Quote").Range.Text = list(1).ToString
答案 0 :(得分:1)
澄清您遇到的问题:
您需要从另一个线程访问ComboBox
和ProgressBar
。您最初使用的BackgroundWorker
显然吞没了您的跨线程错误,或者您在Try-Catch
中吞了它。无论哪种方式,您都将其更改为Thread
并使“交叉线程操作无效”可见。
此错误&#34;跨线程操作无效&#34;当您尝试从其自己的线程访问用户控件时出现。能够修改这些控件很重要,那么我们该怎么做呢?
首先,修改要异步的方法以接受参数。这应该是一个对象,因此您可以将尽可能多的信息传递到任务所需的异步中。
以下是将对象作为参数包含的修改方法。
Public Sub buildReport(list_temp As Object)
在您的代码中,您传入的是ComboxBox文本,而不是对ComboBox的引用。这就是该部分确实有效的原因。然后传入对ProgressBar的引用。当您从异步方法访问进度条时,您没有调用委托。这意味着您必须在UI线程上创建一个更新控件的方法。然后,您声明将从异步方法调用的委托。
以下是启动更新TextBox文本的线程的按钮示例。对于此示例,您需要TextBox
和Button
。
首先,您需要声明委托和该委托的实例。您还需要创建修改所需控件的方法,因为您需要将该方法名称传递给委托实例声明。
Public Delegate Sub SetTextBoxDelegate(Text As String)
Public SetTextbox_UI_Thread As SetTextBoxDelegate = New SetTextBoxDelegate(AddressOf SetTextBox)
Public Sub SetTextBox(Text As String)
TextBox1.Text = Text
End Sub
现在这是启动帖子的按钮点击:
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim t As System.Threading.Thread = New Threading.Thread(AddressOf DoStuff)
t.Start()
End Sub
如您所见,它正在使用方法DoStuff()
启动一个线程。这是调用我们的委托(如果需要)更新文本框的方法。
Public Sub DoStuff()
System.Threading.Thread.Sleep(3000)
If TextBox1.InvokeRequired Then
TextBox1.Invoke(SetTextbox_UI_Thread, "Hello")
Else
TextBox1.Text = "Hello"
End If
End Sub
请注意,我首先检查了InvokeRequired = True
是否因为您可以从UI线程调用此方法,因此您可以像往常一样访问控件。