これは、目的を達成するための (多くの) アプローチの 1 つです。このアプローチでは、UI をそのままにしておくため、正常に更新されます。私は 2 つのプログレス バーのサポートを作成しました。1 つは全体の進行状況 (ファイル数) 用で、もう 1 つは現在の進行状況用です。コードはキャンセルをサポートしています。
必要に応じて使用および変更できます。現状のまま提供されます。
コードは、前述のように、フォームに 2 つのプログレス バーと 2 つのボタン (インストールとキャンセル) があることを前提としています。以下のスナップショットを参照してください。
使用法
コピーしたいすべてのリソースをタスクリストに追加してから、キューを開始します。
AddCopyTask(resourceToCopy1, pathToWhereToCopy1)
AddCopyTask(resourceToCopy2, pathToWhereToCopy2)
...
StartCopyCue()
完全なコード:
Imports System.ComponentModel
Imports System.IO
Public Class Form1
'If you use small file sizes, lower this value to have progress-bar going
Private Const BufferSize As Integer = 4096
Private WithEvents bgCopier As New BackgroundWorker
Private Class WorkerPacket
Public DataRef As Byte()
Public Filename As String
End Class
Private taskList As New List(Of WorkerPacket)
Private _cancel As Boolean = False
'
'-- Setup worker
'
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
bgCopier.WorkerReportsProgress = True
bgCopier.WorkerSupportsCancellation = True
End Sub
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
If bgCopier IsNot Nothing Then
bgCopier.Dispose()
End If
End Sub
'
'-- UI
'
Private Sub Install_Click(sender As System.Object, e As System.EventArgs) Handles Install.Click
'
'-- This is where you initilize the paths and data you want to copy.
'-- For this example I use the same data
'
AddCopyTask(My.Resources.TestData, "c:\test1.dat")
AddCopyTask(My.Resources.TestData, "c:\test2.dat")
AddCopyTask(My.Resources.TestData, "c:\test3.dat")
StartCopyCue()
End Sub
Private Sub CancelCopy_Click(sender As System.Object, e As System.EventArgs) Handles CancelCopy.Click
_cancel = True
If bgCopier.IsBusy Then
bgCopier.CancelAsync()
End If
End Sub
'
'-- The methods to build and perform task-list
'
Private Sub AddCopyTask(data As Byte(), filename As String)
'
'-- Create argument packet for worker
'
Dim wp As New WorkerPacket
wp.DataRef = data
wp.Filename = filename
taskList.Add(wp)
End Sub
Private Sub StartCopyCue()
'
'-- Init total progressbar
'
ProgressBarTotal.Value = 0
ProgressBarTotal.Maximum = taskList.Count
_cancel = False
'
'-- Update UI
'
Install.Enabled = False
CancelCopy.Enabled = True
'
'-- Go
'
CopyBytesToFileMT()
End Sub
Private Sub CopyBytesToFileMT()
'
'-- Get work packet
'
Dim wp As WorkerPacket = taskList(0)
'
'-- Init progress bars
'
ProgressBarCurrent.Value = 0
ProgressBarTotal.Value += 1
'
'-- Start worker
'
If Not _cancel Then
Label1.Text = String.Format("Copying {0}...", Path.GetFileName(wp.Filename))
bgCopier.RunWorkerAsync(wp)
End If
End Sub
Private Sub DoWork(s As Object, e As DoWorkEventArgs) Handles bgCopier.DoWork
Dim wp As WorkerPacket = CType(e.Argument, WorkerPacket)
'
'-- Calculate segments
'
' note: byte().length returns integer which means we're limited to 2 Gb files
'
Dim length As Integer = wp.DataRef.Length
Dim segments As Integer = CInt(Math.Floor(length / BufferSize))
Dim leftOver As Integer = length - segments * BufferSize
Dim bf As Integer = BufferSize
If bf > length Then bf = length
Dim fs As New FileStream(wp.Filename,
FileMode.Create,
FileAccess.Write,
FileShare.None)
'
'-- Copy blocks
'
For i As Integer = 0 To segments - 1
'
'-- Cancelled?
'
If e.Cancel Then
leftOver = 0
Exit For
End If
'
'-- Write a segment to file
'
Dim pos As Integer = i * BufferSize
fs.Write(wp.DataRef, pos, bf)
'
'-- Report current progress
'
bgCopier.ReportProgress(CInt(pos / length * 100))
Next
'
'-- Copy any remainer
'
If leftOver > 0 Then
fs.Write(wp.DataRef, segments * BufferSize, leftOver)
bgCopier.ReportProgress(100)
End If
'
'-- Done
'
fs.Flush()
fs.Dispose()
End Sub
Private Sub CopyProgress(s As Object, e As ProgressChangedEventArgs) Handles bgCopier.ProgressChanged
ProgressBarCurrent.Value = e.ProgressPercentage
End Sub
Private Sub CopyCompleted(s As Object, e As RunWorkerCompletedEventArgs) Handles bgCopier.RunWorkerCompleted
'
'-- Remove task just finished
'
taskList.RemoveAt(0)
'
'-- Do we have another task?
'
If taskList.Count > 0 AndAlso Not _cancel Then
CopyBytesToFileMT()
Else
If _cancel Then
Label1.Text = "Cancelled by user."
Else
Label1.Text = "Completed!"
'
'-- Execute other tasks here...
'
End If
'
'-- Update UI
'
CancelCopy.Enabled = False
Install.Enabled = True
End If
End Sub
End Class
更新:次の変更は、コピー タスクの完了後にプロセスを実行します。必要に応じて変更します。
Imports System.ComponentModel
Imports System.IO
Imports System.Security
Public Class Form1
Private Event AllCompleted()
Private Const BufferSize As Integer = 4096
Private WithEvents bgCopier As New BackgroundWorker
Private WithEvents procUnzipper As New Process
Private Class WorkerPacket
Public DataRef As Byte()
Public Filename As String
End Class
Private taskList As New List(Of WorkerPacket)
Private _cancel As Boolean = False
'
'-- Setup worker
'
Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
bgCopier.WorkerReportsProgress = True
bgCopier.WorkerSupportsCancellation = True
procUnzipper.EnableRaisingEvents = True
procUnzipper.SynchronizingObject = Me
End Sub
Private Sub Form1_FormClosing(sender As Object, e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
bgCopier.Dispose()
procUnzipper.Dispose()
End Sub
'
'-- UI
'
Private Sub Install_Click(sender As System.Object, e As System.EventArgs) Handles Install.Click
'
'-- This is where you initilize the paths and data you want to copy.
'-- For this example I use the same data
'
AddCopyTask(My.Resources.TestData, "c:\test1.dat")
AddCopyTask(My.Resources.TestData, "c:\test2.dat")
AddCopyTask(My.Resources.TestData, "c:\test3.dat")
StartCopyQue()
End Sub
Private Sub CancelCopy_Click(sender As System.Object, e As System.EventArgs) Handles CancelCopy.Click
_cancel = True
If bgCopier.IsBusy Then
bgCopier.CancelAsync()
End If
End Sub
'
'-- The methods to build and perform task-list
'
Private Sub AddCopyTask(data As Byte(), filename As String)
'
'-- Create argument packet for worker
'
Dim wp As New WorkerPacket
wp.DataRef = data
wp.Filename = filename
taskList.Add(wp)
End Sub
Private Sub StartCopyQue()
'
'-- Init total progressbar
'
ProgressBarTotal.Value = 0
ProgressBarTotal.Maximum = taskList.Count
_cancel = False
'
'-- Update UI
'
Install.Enabled = False
CancelCopy.Enabled = True
'
'-- Go
'
CopyBytesToFileMT()
End Sub
Private Sub CopyBytesToFileMT()
'
'-- Get work packet
'
Dim wp As WorkerPacket = taskList(0)
'
'-- Init progress bars
'
ProgressBarCurrent.Value = 0
ProgressBarTotal.Value += 1
'
'-- Start worker
'
If Not _cancel Then
Label1.Text = String.Format("Copying {0}...", Path.GetFileName(wp.Filename))
bgCopier.RunWorkerAsync(wp)
End If
End Sub
Private Sub DoWork(s As Object, e As DoWorkEventArgs) Handles bgCopier.DoWork
Dim wp As WorkerPacket = CType(e.Argument, WorkerPacket)
'
'-- Calculate segments
'
' note: byte().length returns integer which means we're limited to 2 Gb files
'
Dim length As Integer = wp.DataRef.Length
Dim segments As Integer = CInt(Math.Floor(length / BufferSize))
Dim leftOver As Integer = length - segments * BufferSize
Dim bf As Integer = BufferSize
If bf > length Then bf = length
Dim fs As New FileStream(wp.Filename,
FileMode.Create,
FileAccess.Write,
FileShare.None)
'
'-- Copy blocks
'
For i As Integer = 0 To segments - 1
'
'-- Cancelled?
'
If e.Cancel Then
leftOver = 0
Exit For
End If
'
'-- Write a segment to file
'
Dim pos As Integer = i * BufferSize
fs.Write(wp.DataRef, pos, bf)
'
'-- Report current progress
'
bgCopier.ReportProgress(CInt(pos / length * 100))
Next
'
'-- Copy any remainer
'
If leftOver > 0 Then
fs.Write(wp.DataRef, segments * BufferSize, leftOver)
bgCopier.ReportProgress(100)
End If
'
'-- Done
'
fs.Flush()
fs.Dispose()
End Sub
Private Sub CopyProgress(s As Object, e As ProgressChangedEventArgs) Handles bgCopier.ProgressChanged
ProgressBarCurrent.Value = e.ProgressPercentage
End Sub
Private Sub CopyCompleted(s As Object, e As RunWorkerCompletedEventArgs) Handles bgCopier.RunWorkerCompleted
'
'-- Remove task just finished
'
taskList.RemoveAt(0)
'
'-- Do we have another task?
'
If taskList.Count > 0 AndAlso Not _cancel Then
CopyBytesToFileMT()
Else
If _cancel Then
Label1.Text = "Cancelled by user."
Else
Label1.Text = "Unzipping..."
'
'-- Start process
'
ProgressBarTotal.Style = ProgressBarStyle.Marquee
Dim arg As String = String.Format(" x ""{0}"" -mmt -aoa -o ""{1}""",
"theZipFile.7z",
"installpath\")
procUnzipper.StartInfo.FileName = "...\7z.exe"
procUnzipper.StartInfo.Arguments = arg
procUnzipper.Start()
End If
End If
End Sub
Private Sub UnzipCompleted(s As Object, e As EventArgs) Handles procUnzipper.Exited
'just for example
'this following require syncronizationobject set, see form_load
RaiseEvent AllCompleted()
End Sub
Private Sub Done() Handles Me.AllCompleted
'
'-- Update UI
'
Label1.Text = "Completed!"
ProgressBarTotal.Style = ProgressBarStyle.Blocks
CancelCopy.Enabled = False
Install.Enabled = True
End Sub
End Class