|
■No66879 (taka さん) に返信
> 上に現在試しているソースコードそのまま貼り付けてみました。
投稿された Class は、2 つとも Form なのですよね?
> 「ウィンドウハンドルが作成される前、コントロールでinvokeまたはbegininvokeを呼び出せません」
恐らくは、IsHandleCreated が False の状態だったのかと。
> 'スレッドで開始するメソッド'
> Private Sub StartThread()
> '処理中ダイアログが表示されるまでCloseMsgDialogメソッドをブロックする'
> AddHandler Me.Activated, AddressOf _form_Activated
> '処理中ダイアログを表示する'
> Application.Run(Me)
> End Sub
上記 Me のインスタンスは、メインスレッドで生成され、
ProcInfo.P_ProcInfoMsg フィールドで管理されていますので、
それをワーカー側で扱うのは望ましくありません。
ワーカー側で表示されるフォームは、ワーカー側で管理すべきかと。
> '呼出画面での処理
やりたいことは
pd = New 進捗管理クラス()
pd.BackColor = 進捗フォームの背景色
pd.ShowMsgDialog() '進捗フォームを別スレッドで非同期表示
' :
'メインスレッド側の処理
' :
pd.ClosMsgDialog() '進捗フォームの終了要求
で宜しいでしょうか?
だとすればこの場合、「進捗管理クラス」を Form にするのではなく、
「進捗管理クラスが、内部で Private な Form を表示させる」だけにします。
単純な実装としてはこんな感じ。
Imports System.Drawing
Imports System.ComponentModel
Public Class Form1
Inherits Form
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
'実際には匿名型ではなく、明示的な型を用意した方が良いでしょう
Dim 設定値 = New With {
.BackColor = Color.Cyan,
.ImageFile = "C:\Icon_Graphic\image.gif",
.MsgFont = New Font("MS UI GothicD", 12, FontStyle.Italic)
}
'下記では、テストしやすいよう BackgroundWorker を使っていますが
'実際には再利用しやすいように 進捗管理クラス を別途用意しておき、
'そのクラス内でワーカースレッドを作成するようにしてみてください
Me.BackgroundWorker1.WorkerSupportsCancellation = True
Me.BackgroundWorker1.RunWorkerAsync(設定値)
MsgBox("エラーメッセージなど")
'終了依頼
BackgroundWorker1.CancelAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
Dim 設定値 = e.Argument
Dim bgw = DirectCast(sender, BackgroundWorker)
Dim f As New Form2()
f.BackColor = 設定値.BackColor
f.Label1.Font = 設定値.MsgFont
f.PictureBox1.LoadAsync(設定値.ImageFile)
f.Timer1.Interval = 72
f.Timer1.Start()
AddHandler f.Timer1.Tick, Sub() If bgw.CancellationPending Then f.Close()
f.Timer1.Start()
Application.Run(f)
End Sub
'外部から直接呼ばれないよう、Private Class にした方が安全かも
'Private Class Form2
' Inherits Form
' ' :
'End Sub
End Class
ただし、これはあまり好ましい実装ではありません。
メイン画面で時間のかかる処理が行われれば、アプリケーションが
暫く応答なし状態になる点は変わりませんし、先の投稿で問題視されていた
進捗画面とメイン画面の ZOrder 順に関する問題を抱える結果にもなるからです。
先にも少し書きましたが、UI の扱いはメインスレッドに任せておき、
時間のかかる作業の方をワーカースレッドに任せるのが、本来の対処方法です。
> 処理にはデータ表示を含んでおり、画面部品に依存しております。
データ表示だけ、相手に依頼してあげてください。
ワーカースレッドが、自身でデータを表示するのではなく、
ワーカースレッドが、UI スレッドにデータを BeginInvoke で渡して、
UI スレッド自身に表示させる形をとります。
(InvokeRequired プロパティの解説なども参考に)
> 1秒で終了してしまうこともあります。
ちなみに Windows 8 のストアアプリでは、
わずかでも時間のかかる可能性のある処理(50ミリ秒以上が目安)は、
全て非同期処理にすることが求められています。
|