これは元の質問に基づいています。ボタンのクリックにBackgroundWorkerを追加して、GetEasyPostServicesをUI以外のスレッドで実行するようにしました。ここでの要点は、UI呼び出しを適切に呼び出す方法です。下の3つの方法はそれを実証しています。
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
' this method is running on the UI thread as it handles a UI event
Dim bw As New System.ComponentModel.BackgroundWorker()
AddHandler bw.DoWork, New System.ComponentModel.DoWorkEventHandler(Sub(oo, ee) GetEasyPostServices())
' this call causes GetEasyPostServices to run on a non-UI thread
bw.RunWorkerAsync()
End Sub
Private Sub GetEasyPostServices()
' running on a non-UI thread. Any UI calls must be invoked
Cursor.Current = Cursors.WaitCursor
Try
Dim frAddress As New Dictionary(Of String, Object)() From {
{"street1", "12345 Hill Dr"},
{"street2", ""},
{"city", "sometown"}}
Dim toAddress As New Dictionary(Of String, Object)() From {
{"street1", sAdd1},
{"city", sCity},
{"state", sRegion},
{"verifications", New List(Of String)() From {"delivery"}}}
Dim package As New Dictionary(Of String, Object)
If GlobalVariables.giLength > 0 Then
package.Add("length", GlobalVariables.giLength.ToString)
package.Add("width", GlobalVariables.giWidth.ToString)
package.Add("height", GlobalVariables.giHeight.ToString)
package.Add("weight", (sLbs * 16) + sOz)
End If
EasyPostGetServices(frAddress, toAddress, package)
If EasyPostShipment.rates.Count > 0 Then
' hide the UI invocation logic in methods
updateListView()
Else
MsgBox("Based on your inputs or preferences, no shipping services were available. Shipping services shown ignore your preferences. If none are shown, there are no shipping services available for this order.")
clearAndFocusTbOrder()
End If
Finally
Cursor.Current = Cursors.Default
End Try
End Sub
' these methods manage their own UI invocation.
Private Sub updateListView()
If lvRates.InvokeRequired Then
lvRates.Invoke(New Action(AddressOf updateListView))
Else
lvRates.Visible = True
lvRates.Items.Clear()
For Each rate As Rate In EasyPostShipment.rates
lvRates.Items.Add(New ListViewItem({rate.carrier, rate.rate, UCase(rate.service), rate.id}))
Next
SortListView()
lvRates.Items(0).Selected = True
Button1.Visible = True
End If
End Sub
Private Sub SortListView()
If lvRates.InvokeRequired Then
lvRates.Invoke(New Action(AddressOf SortListView))
Else
lvRates.Sort()
End If
End Sub
Private Sub clearAndFocusTbOrder()
If tbOrderID.InvokeRequired Then
tbOrderID.Invoke(New Action(AddressOf clearAndFocusTbOrder))
Else
tbOrderID.Clear()
tbOrderID.Focus()
End If
End Sub
これは、何を、どこで、なぜ呼び出すのかということです。あなたの例では、GetEasyPostServicesがUIで起動されたかどうかは不明でした。そうしないとUI呼び出しを正しく呼び出す方法を示すことができませんでした。 UIスレッドが現在UIスレッドにないので、UI呼び出しを呼び出す必要があります。それが「理由」です。
また、不要な処理やUIスレッドのハングアップを防ぐために、UIスレッドで最小限のコードを実行することが重要です。元の設定ですべてのコードが1回実行された後、すべてのUIスレッドで実行されました。
出典
2017-12-07 20:19:44
djv
あなた自身で答えることができます:ブレークポイントを設定し、コールスタックを調べます。あなたはDataSourceで作業することができ、B)あなたは幅*などを* numbers * – Plutonix
「GlobalVariables」として保存できるので、DataGridViewがより良い選択となるようです。それはコードのにおいです。 – LarsTech
あなたはサブ呼び出し自体を伝えているので、2回呼び出されることは意味がありますか? invokeが必要な場合、GetEasyPostServicesは別のスレッド上の別のコピーを呼び出します。したがって、2つの実行が行われます。 2回目の実行は、呼び出しを必要としないスレッドで実行されているため、elseブロックにドロップされて終了します。 – soohoonigan