zoukankan      html  css  js  c++  java
  • 使用BackgroundWorker做多线程,SoEasy

      最近我们在学校实验室学习,老师要求用uc/os-II实现一个多线程,恰好在暑期实习的公司也做过多线程的一个东西,于是想着分享出来,同时也想把这个实例记录下来,以后用到的时候再看看。

      首先开始写这个实例之前,我想先说说为什么要用这个BackgroundWorker类。我们经常会遇到这样的情况,就是后台有大量的计算,而前台要不停的根据后台的进度调整前台的界面显示,于是微软针对这个情况实现了BackgroundWorker这个类来帮助程序员方便的解决这个问题。

      对于这个问题和这个类,微软的MSDN是这样描述的:BackgroundWorker 类允许您在单独的专用线程上运行操作。耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用 BackgroundWorker 类方便地解决问题。

      我在公司做的这个东西的目的是这样的:公司以前做了一个教务管理系统,但以前使用的是Access数据库,但现在要升级成SQLserver数据库,将以前的acess数据库中的数据导SQLserver中,于是就需要这么一个界面显示导入数据的进度。  

      以前没做过这东西,于是瞎子摸象,用VS2010用VB拖控件做,做着做着,问题不断涌现,我的想法是用表格做,再在里面添加想要的控件,这样看起来比较整齐一些,但是这样做麻烦,让同事解决这些问题时,他说你自己做一个用户控件就行了,不需要这么麻烦。哎,有时候,人的想法可以,但是实施起来麻烦,经过他这么一指点,唰唰唰,几下就做了一个用户控件,然后我开始布局这些控件的位置,他给我的建议是:进度条的多少根据后台数据库的数据的多少动态生成,这个好办,好在我学过java,做过类似的东西,不过那时候界面是定死的,控件不能随外界因素变化。好了,我感觉我的废话有点多了,开始这个实例。

      首先在这个界面中最重要的就是这个进度条,首先我们设计这个进度条组合控件,在此以截图说明:

      以上这个就是我们要的进度条组合控件,简单说明一下,Lable:显示是哪类数据;后面那个图标是动态的,说明数据正在处理中,logFile:打开日志文件;下面是进度条,后面是百分比显示。

      这个做好之后,你可以将这个控件加到其他windows窗口上,布局你自己定,但是要经过一定的计算,确定他们的相对位置。

      经过做这个东西,我领悟到一个原则,就是一个控件你的所有功能只对你自身进行操作,不要牵扯其他的东西,我做这个就是只对我做的控件进行操作,从做这个学到这个也算一个收获,以下是对这个控件的处理代码,用vb写的:

      ProgressControl.vb

      

    Imports System.Drawing
    Imports System.Windows.Forms
    Imports System.ComponentModel
    Imports System.Diagnostics
    Imports System.IO
    
    
    Public Class ProgressControl
    
        'click the logButton, then open the logFile 
        Private logFile As String
    
        'when the num come to maxValue, the progress is 100%
        Private maxValue As Integer = 1
    
        'record the finishing count
        Private finishCount As Integer = 1
    
        'handle of set the statePic' image
        Private Delegate Sub SetPicImageHandle(ByVal img As Image)
    
        'set the statePic image
        Private Sub SetPicImage(ByVal img As Image)
            If Me.statePic.InvokeRequired Then
                Dim handle As SetPicImageHandle = New SetPicImageHandle(AddressOf SetPicImage)
                Me.statePic.Invoke(handle, New Object() {img})
            Else
                Me.statePic.Image = img
            End If
        End Sub
    
        'handle of set the statePic' visible
        Private Delegate Sub SetPicVisibleHandle(ByVal v As Boolean)
    
        'set the statePic' visible
        Private Sub SetPicVisible(ByVal visible As Boolean)
            If Me.statePic.InvokeRequired Then
                Dim handle As SetPicVisibleHandle = New SetPicVisibleHandle(AddressOf SetPicVisible)
                Me.statePic.Invoke(handle, New Object() {visible})
            Else
                Me.statePic.Visible = visible
            End If
        End Sub
    
        'handle of set the logButton' visible
        Private Delegate Sub SetLogButtonVisibleHandle(ByVal v As Boolean)
    
        'set the logButton' visible
        Private Sub setLogButtonVisible(ByVal visible As Boolean)
    
            If Me.logButton.InvokeRequired Then
                Dim handle As SetLogButtonVisibleHandle = New SetLogButtonVisibleHandle(AddressOf setLogButtonVisible)
                Me.logButton.Invoke(handle, New Object() {visible})
            Else
                Me.logButton.Visible = visible
            End If
    
        End Sub
    
        'open the log file
        Private Sub logButton_Click(sender As System.Object, e As System.EventArgs) Handles logButton.Click
    
            Try
                Process.Start(logFile)
            Catch ex As FileNotFoundException
                MessageBox.Show("FileNotFoundException!")
            Catch ex As Win32Exception
                MessageBox.Show("the file isn'n exist or the file name is wrong!", "Win32Exception")
            End Try
    
        End Sub
    
        'set the statePic' image and whether show it or not
        Public Sub SetStatePic(ByVal img As Image, ByVal visible As Boolean)
    
            'set statePic' image
            SetPicImage(img)
    
            'set the statePic' visible
            SetPicVisible(visible)
    
        End Sub
    
        'set the progressbar' value and percentLabel' text
        Public Sub SetProgressValue(ByVal value As Integer)
    
            If value < 0 Then
                Throw New ArgumentException("the Sub SetProgressValue()' parameter is wrong!")
            Else
                Try
    
                    Dim finishPercent As Integer = value / maxValue * 100
                    Dim progressBarPercnet As Integer = progressBar.Step * finishCount
    
                    If finishPercent = 100 Then
    
                        progressBar.Value = 100
                        percentLabel.Text = "100%"
    
                    ElseIf finishPercent > 0 AndAlso finishPercent = progressBarPercnet Then
    
                        'change progressBar' length
                        progressBar.PerformStep()
    
                        'change the percentLable' text
                        percentLabel.Text = (finishCount * progressBar.Step).ToString & "%"
                        finishCount = finishCount + 1
    
                    End If
    
                Catch ex As OverflowException
    
                    MessageBox.Show(ex.Message)
    
                Catch e As Exception
    
                    MessageBox.Show(e.Message)
    
                End Try
                
            End If
    
        End Sub
    
        'whether show the logButton or not
        Public Sub SetLogButton(ByVal visible As Boolean)
    
            logButton.Visible = visible
    
        End Sub
    
        'set the logFileName
        Public Sub SetLogFileName(ByVal name As String)
    
            logFile = name
    
        End Sub
    
        'set the itemLabel' text
        Public Sub SetItemName(ByVal name As String)
    
            itemLabel.Text = name
    
        End Sub
    
        'handle of set the progressBar' step
        Private Delegate Sub AppendProgressBarStepHandle(ByVal value As Integer)
    
        'set the progressBar' step
        Private Sub AppendProgressBarStep(ByVal value As Integer)
            If Me.progressBar.InvokeRequired Then
                Dim handle As AppendProgressBarStepHandle = New AppendProgressBarStepHandle(AddressOf AppendProgressBarStep)
                Me.progressBar.Invoke(handle, New Object() {value})
            ElseIf value <= 0 Then
                Throw New ArgumentException("the Sub AppendProgressBarStep()' parameter is wrong!")
            Else
                Me.progressBar.Step = value
            End If
        End Sub
    
        'handle of set the maxValue
        Private Delegate Sub AppendMaxValueHandle(ByVal value As Integer)
    
        'set the maxValue
        Private Sub AppendMaxValue(ByVal value As Integer)
            If Me.progressBar.InvokeRequired Then
                Dim handle As AppendMaxValueHandle = New AppendMaxValueHandle(AddressOf AppendMaxValue)
                Me.progressBar.Invoke(handle, New Object() {value})
            ElseIf value <= 0 Then
                Throw New ArgumentException("the Sub AppendMaxValue()' parameter is wrong!")
            Else
                Me.maxValue = value
            End If
        End Sub
    
        'set the maxValue
        Public Sub SetMaxValue(ByVal value As Integer)
            AppendMaxValue(value)
        End Sub
    
        Public Sub SetProgressBarStep(ByVal value As Integer)
            AppendProgressBarStep(value)
        End Sub
    
    End Class
    

      

      上面的注释是用英语写的,但都是经常见的英语单词,不难理解,代码是VB.NET,vb很好理解,难的就是其中的委托,有兴趣的朋友可以看看这部分内容,感觉很有用,在这不多讲了。因为公司的这个系统是为日本做的,所以他们用的是日系windows操作系统,为了不因汉字引起问题,所以同事让我以英语加注释,很简单,没什么复杂的,我本人也是希望东西越简单越好,整那么复杂干嘛,想显示自己的高端,不,我可不这样想的。乔布斯设计苹果的原则就是简单,说这话感觉有点自恋了,呵呵...

      为了不占用太大的空间,我将图片缩小了,但是还能看到其中的内容,可以说明问题就行了。再看看怎样布局这些控件的,这部分就要认真计算一下:

      ProgressContainer.vb

      

    Imports System.Drawing
    Imports System.Windows.Forms
    Imports System.Threading
    
    Public Class ProgressContainer
        Implements IProgress
    
        'operationControl' size
        Private Const OPERATIONCONTROL_HEIGHT As Integer = 70
    
        'controls' space value
        Private Const SPACELENGTH As Integer = 30
    
        'totalStateLabel' max length
        Private Const TOTALSTATE_MAXLENGTH = 230
    
        'the panel' width of progressContainer
        Private Const PANEL_WIDTH = 500
    
        'the progressControl' count can be show in the panel
        Private Const PROGRESSCONTROL_MAXCOUNT = 5
    
        'the closeFlag is used to control whether the closeBox is available
        Private closeFlag As Boolean = False
    
    
        Sub New()
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
    
            'set bottom controls' properties
            totalStateLabel.Text = "处理中..."
            totalStatePic.Image = Global.ProgressClass.My.Resources.loading
            OKButton.Enabled = False
    
            'set the MinimizeBox and MaximizeBox' Initial state
            Me.MinimizeBox = True
            Me.MaximizeBox = False
    
            'the TotalProgress form can't be closed
            closeFlag = False
    
        End Sub
    
    
        Private Sub TotalProgress_Unload(ByVal sender As System.Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.FormClosing
    
            If closeFlag = True Then
    
                'MessageBox.Show("make sure to close the dialog box", "CloseDialog", MessageBoxButtons.YesNo)
    
                If MessageBox.Show("make sure to close the dialog box", "CloseDialog", MessageBoxButtons.YesNo) = Windows.Forms.DialogResult.Yes Then
                    Return
                Else
                    e.Cancel = True
                End If
    
            Else
                e.Cancel = True
            End If
    
        End Sub
    
        Private Sub OKButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles OKButton.Click
            Me.Close()
        End Sub
    
        'the first string of Dictionary is progressControl' Name,the second is logFileName
        Public Sub CreateNewProgress(allProgress As System.Collections.Generic.Dictionary(Of String, String)) Implements IProgress.CreateNewProgress
    
            Dim progressControl As ProgressControl
            Dim index As Integer = 0
            Dim progressControlMaxCount As Integer = 0
    
            If allProgress.Count <= 0 Then
                MessageBox.Show("the Sub sendOperatonItems()' parameter has no values, please check it!")
            End If
    
            Try
                For Each key As String In allProgress.Keys
    
                    progressControl = New ProgressControl()
    
                    'set the progressControl' name
                    progressControl.SetItemName(key)
    
                    'set the logFile name
                    progressControl.SetLogFileName(allProgress(key))
    
                    'set the progressBar' value and percentLabel' text
                    progressControl.percentLabel.Text = "0%"
    
                    'set the statePic' image and show it or not
                    progressControl.SetStatePic(Global.ProgressClass.My.Resources.loading, False)
    
                    'whether show the logButton
                    progressControl.SetLogButton(False)
    
                    'set operationControl’location
                    progressControl.Top = index * OPERATIONCONTROL_HEIGHT
    
                    'add the progressControl to the progressContainer' panel
                    panel.Controls.Add(progressControl)
    
                    'set the operationControl' index to easy access it
                    panel.Controls.SetChildIndex(progressControl, index)
    
                    index = index + 1
    
                Next
    
                'set the value of most can display of progressControl
                If allProgress.Count > 5 Then
                    progressControlMaxCount = PROGRESSCONTROL_MAXCOUNT
                Else
                    progressControlMaxCount = allProgress.Count
                End If
    
                'set totalStateLabel totalStatePic and OKButton' location
                totalStateLabel.Location = New Point(2 * SPACELENGTH, progressControlMaxCount * OPERATIONCONTROL_HEIGHT + 2 * SPACELENGTH)
                totalStatePic.Location = New Point(Left + TOTALSTATE_MAXLENGTH + 4 * SPACELENGTH, progressControlMaxCount * OPERATIONCONTROL_HEIGHT + 2 * SPACELENGTH)
                OKButton.Location = New Point(Left + TOTALSTATE_MAXLENGTH + 6 * SPACELENGTH, progressControlMaxCount * OPERATIONCONTROL_HEIGHT + 2 * SPACELENGTH)
    
                'set the ProgressContainer' size
                Me.Size = New Size(PANEL_WIDTH + 2 * SPACELENGTH, progressControlMaxCount * OPERATIONCONTROL_HEIGHT + 5 * SPACELENGTH)
    
            Catch ex As InvalidOperationException
                MessageBox.Show("InvalidOperationException!")
            End Try
    
        End Sub
    
        Public Sub SetStartImg(progressNum As Integer) Implements IProgress.SetStartImg
    
            Dim progressControl As ProgressControl
    
            Try
                progressControl = panel.Controls.Item(progressNum)
    
                'change the statePic' image and show it
                progressControl.SetStatePic(Global.ProgressClass.My.Resources.loading, True)
            Catch ex As Exception
                MessageBox.Show("the value or type of Sub start()' parameter is wrong,please check it!")
            End Try
    
        End Sub
    
        Public Sub SetProgressValue(progressNum As Integer, progressValue As Integer) Implements IProgress.SetProgressValue
    
            Dim progressControl As ProgressControl
    
            Try
                progressControl = panel.Controls.Item(progressNum)
    
                'change the progressBar' value and percnetLabel' text
                progressControl.SetProgressValue(progressValue)
            Catch ex As Exception
                MessageBox.Show("the value or type of Sub sendProgressValue()' first parameter is wrong,please check it!")
            End Try
    
        End Sub
    
    
        Public Sub SetResultImg(progressNum As Integer, result As Boolean) Implements IProgress.SetResultImg
    
            Dim progressControl As ProgressControl
    
            Try
                progressControl = panel.Controls.Item(progressNum)
    
                'change the statePic to show the statePic' result
                If result = True Then
                    progressControl.SetStatePic(Global.ProgressClass.My.Resources.yes, True)
                Else
                    progressControl.SetStatePic(Global.ProgressClass.My.Resources.no, True)
                End If
    
            Catch ex As Exception
                MessageBox.Show("the value or type of Sub sendOperationResult()' first parameter is wrong,please check it!")
            End Try
    
        End Sub
    
        Public Sub FinishAllProgress() Implements IProgress.FinishAllProgress
    
            Dim progressControl As ProgressControl
    
            For i As Integer = 0 To panel.Controls.Count - 1
    
                progressControl = panel.Controls.Item(i)
    
                'to show the logButton
                progressControl.SetLogButton(True)
    
            Next
    
            'set the properties of totalStateLabel, totalStatePic and OkButton
            totalStateLabel.Text = "处理完了"
            totalStatePic.Image = Global.ProgressClass.My.Resources.yes
            OKButton.Enabled = True
    
            'the TotalProgress form can be closed
            closeFlag = True
    
        End Sub
    
    
        Public Sub SetMaxValue(progressNum As Integer, value As Integer) Implements IProgress.SetMaxValue
    
            Dim progressControl As ProgressControl
    
            progressControl = panel.Controls.Item(progressNum)
    
            'set the maxValue
            progressControl.SetMaxValue(value)
    
        End Sub
    
        Public Sub SetProgressBarStep(progressNum As Integer, value As Integer) Implements IProgress.SetProgressBarStep
    
            Dim progerssControl As ProgressControl
    
            progerssControl = panel.Controls.Item(progressNum)
    
            'set progressBar' step
            progerssControl.SetProgressBarStep(value)
    
        End Sub
    
    End Class
    

      

      代码注释还是英文,方法名都是见名知意,在公司学的另一个就是不管给什么起名字,都要让别人知道你这里是干什么的,不能明白全部,也要略知一二。还有就是你的代码风格,要整齐有序。这个布局是这样设计的:按照你要处理的数据类型多少,自动显示多少,超过五个进度条组合控件时,只显示五个,多出的显示一个滚动条,然后拖动滚动条你就会看到多出的那些。

      好了,这个前台显示界面就算做好了,说明一下我只负责制作这个界面,那要给别人用,所以没有必要让别人知道其中的内容,只要设置一些接口即可,别人想要对你这个界面做怎样的操作,给他个接口就行。下面是这些接口:

      IProgress.vb

      

    Public Interface IProgress
    
        'set all ' name and logfiles' name
        Sub CreateNewProgress(ByVal allProgress As Dictionary(Of String, String))
    
        'set the statePic' image when start one progress
        Sub SetStartImg(ByVal progressNum As Integer)
    
        'set the progress value of the progress item you want 
        Sub SetProgressValue(ByVal progressNum As Integer, ByVal progressValue As Integer)
    
        'set the result' image of one progress when it was finish
        Sub SetResultImg(ByVal progressNum As Integer, ByVal result As Boolean)
    
        'when you complete all Progress, you can call this sub
        Sub FinishAllProgress()
    
        'set the progressBar' step
        Sub SetProgressBarStep(ByVal progressNum As Integer, ByVal value As Integer)
    
        'set the maxValue
        Sub SetMaxValue(ByVal progressNum As Integer, ByVal value As Integer)
    
    End Interface
    

      

      其实上面这些只是为我们应用BackgroundWorker做铺垫,好了,看看我们的主界面是怎样的:

      没搞错吧,就一个button,对,就只有这个,因为这个只是对我们上面做的那个界面的测试,对这个界面测试就要用到多线程。我们先来看看主界面的代码:

      MainForm.vb

      

    Imports ProgressClass
    Imports ProgressClass.ProgressContainer
    Imports System.ComponentModel
    
    Public Class MainForm
    
        Dim check As ProgressContainer
        Dim progresses As Dictionary(Of String, String)
    
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
    
            worker.WorkerReportsProgress = True
            worker.WorkerSupportsCancellation = True
    
            'set the total form' 
            startProgress()
    
            'start the disposing program of Dowork' event 
            worker.RunWorkerAsync()
    
        End Sub
    
    
        Private Sub worker_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles worker.DoWork
    
            Dim workerTmp As BackgroundWorker = CType(sender, BackgroundWorker)
    
            'call the dispoding program of event 
            Work(workerTmp)
    
        End Sub
    
        'receive the updating progress notice
        Private Sub worker_ProgressChanged(sender As System.Object, e As System.ComponentModel.ProgressChangedEventArgs) Handles worker.ProgressChanged
            Dim index As Integer = CType(e.UserState, Integer)
            Dim progressValue As Integer = CType(e.ProgressPercentage, Integer)
    
            'update the progressBar' value
            check.SetProgressValue(index, progressValue)
    
        End Sub
    
        Private Sub worker_RunWorkerCompleted(sender As System.Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles worker.RunWorkerCompleted
            'when the Work was completed, change the totalStateLabel' text, totalStatePic' image and make the OKButton visible
            check.FinishAllProgress()
        End Sub
    
        Private Sub startProgress()
    
            check = New ProgressContainer()
            progresses = New Dictionary(Of String, String)()
    
            'add the items' name and log files' position
            progresses.Add("1", "e:/aaa.txt")
            progresses.Add("3", "456")
    
            check.CreateNewProgress(progresses)
            check.Show()
        End Sub
    
        Private Sub Work(ByVal workerTmp As BackgroundWorker)
    
            If progresses.Count > 0 Then
    
                For i As Integer = 0 To progresses.Count - 1
    
                    check.SetStartImg(i)
                    check.SetMaxValue(i, 1000)
                    check.SetProgressBarStep(i, 9)
    
                    For j As Integer = 0 To 1000
                        System.Threading.Thread.Sleep(10)
    
                        Try
                            workerTmp.ReportProgress(j, i)
                        Catch ex As InvalidOperationException
                            MessageBox.Show("InvalidOperationException")
                        End Try
    
                        workerTmp.ReportProgress(j, i)
                    Next
    
                    check.SetResultImg(i, True)
    
                Next
    
            End If
    
        End Sub
    
    End Class
    

      

      下面重点介绍一下上面这部分代码,不能本末倒置嘛,要不然就文不对题了,呵呵...

      因为这个界面只有一个按钮,所以程序应该是从单击这个按钮开始的:

      Button1_Click()这个方法响应Check按钮,单击后,先做一些初始化工作,

      worker.WorkerReportsProgress :获取或设置一个值,该值指示 BackgroundWorker 能否报告进度更新。

          worker.WorkerSupportsCancellation :获取或设置一个值,该值指示 BackgroundWorker是否支持异步取消。

      startProgress()是对前台界面的初始化,基本上初始化的工作都是在ProgressContainer.vb完成的,你可以沿着调用关系去看看这些。

      worker.RunWorkerAsync()就是执行后台操作,直接运行work()方法,其中就是一些循环,我只是模拟,目的是为了证明我这个程序没错,也不能说没错,只能说是能完成基本的操作,因为我这个程序还没有经过专业人员的测试,所以不敢打这个包票。

      workerTmp.ReportProgress(j, i)就是传给前台的一些数据,这个方法引发ProgressChanged事件,第一个参数是进度条值,第二个是操作哪个进度条。

      Dim index As Integer = CType(e.UserState, Integer)

         Dim progressValue As Integer = CType(e.ProgressPercentage, Integer)

      以上这两行代码取到这个进度条的标志值和进度值。

      check.SetProgressValue(index, progressValue) :就是对这个进度条组合控件进行操作。

        RunWorkerCompleted() : 当后台操作已完成、被取消或引发异常时发生,我们这部分只是对结束后台运算时,前台所要最后做的处理,我们只调用了check.FinishAllProgress()。

      这部分算是介绍完了,看看效果:

      如果您有什么意见或者建议,请给我留言,相互学习,对我也是一个提高。

      

  • 相关阅读:
    [转载]android开发手册
    [转载]windows phone7 学习笔记10——生命周期/墓碑化
    [转载]Windows Phone 系列 本地数据存储
    【转载】windows phone7 学习笔记12——推送通知服务
    【转载】windows phone7 学习笔记15——Bing Maps
    [转载]WP7交互特性浅析及APP设计探究
    【】windows phone7 学习笔记11——启动器与选择器
    [转载]支持的 Windows Phone 媒体编解码器
    【转载】wp7屏幕截图代码
    【转载】windows phone7 学习笔记14——地理位置服务与反应性扩展框架
  • 原文地址:https://www.cnblogs.com/dofi/p/2218727.html
Copyright © 2011-2022 走看看