VB.NET学习笔记:异步委托实现等待窗体(loading界面),执行任务超时可以取消操作

为了给用户提供更好的体验,读取数据库等程序需要长时间来执行的操作,需要弹出一个等待界面。可以一边执行需要等待的操作,一边显示一个等待界面。当执行完毕时等待界面消失。用户可以提前取消操作,还可以设置操作的最大等待时间,若超过指定时间仍没完成操作可结束当前操作。
如图所示:
VB.NET学习笔记:异步委托实现等待窗体(loading界面),执行任务超时可以取消操作_第1张图片
VB.NET学习笔记:异步委托实现等待窗体(loading界面),执行任务超时可以取消操作_第2张图片
VB.NET学习笔记:异步委托实现等待窗体(loading界面),执行任务超时可以取消操作_第3张图片
从上图可以看到等待窗体是透明的。
首先新一个Windows窗体应用项目,包含两个窗体:等待窗体LoadForm和主窗体MainForm。
等待窗体界面加入一个pictureBox控件并设置其SizeMode属性值为AutoSize,让图片框能根据图片大小自动伸缩,然后添加一张没有背景的GIF图片;再加入2个Label控件用于显示提示信息(可以自定义)和操作时间;再加入一个Button控件用于取消操作。
对窗体的FormBorderStyle属性设置为无边框,StartPosition设置为显示到父窗体中间,ShowInTaskbar设置为不在任务栏显示,最重点的是TransparencyKey属性,用于设置窗体透明区域颜色,我们把他设置为窗体背景色,这样呈现出来的就是一个透明的窗体了。
如图:
VB.NET学习笔记:异步委托实现等待窗体(loading界面),执行任务超时可以取消操作_第4张图片
在等待窗口代码区添加如下代码:

Public Class LoadForm

    Private _MaxWaitTime As Integer
    Private _WaitTime As Integer
    Private _CancelEnable As Boolean
    Private _AsyncResult As IAsyncResult
    Private _method As MethodInvoker
    Public Property Message As String
    Public Property TimeSpan As Integer


    Public Sub New(ByVal method As MethodInvoker, ByVal maxWaitTime As Integer, ByVal waitMessage As String, ByVal cancelEnable As Boolean, ByVal timerVisable As Boolean)
        maxWaitTime *= 1000
        Initialize(method, maxWaitTime, waitMessage, cancelEnable, timerVisable)
    End Sub

    Private Sub Initialize(ByVal method As MethodInvoker, ByVal maxWaitTime As Integer, ByVal waitMessage As String, ByVal cancelEnable As Boolean, ByVal timerVisable As Boolean)
        InitializeComponent()
        '无边框
        Me.FormBorderStyle = FormBorderStyle.None
        '起始位于父窗体中间
        Me.StartPosition = FormStartPosition.CenterParent
        '不在任务栏显示
        Me.ShowInTaskbar = False
        '窗体透明区域颜色为窗体背景色
        Me.TransparencyKey = Me.BackColor

        Me.labMessage.Text = waitMessage
        TimeSpan = 500
        Message = String.Empty
        _CancelEnable = cancelEnable
        _MaxWaitTime = maxWaitTime
        _WaitTime = 0
        _method = method
        Me.LikCancel.Visible = _CancelEnable
        Me.labTimer.Visible = timerVisable
        Me.Timer1.Interval = TimeSpan
        Me.Timer1.Start()
    End Sub

    Private Sub LikCancel_LinkClicked(sender As Object, e As LinkLabelLinkClickedEventArgs) Handles LikCancel.LinkClicked
        Me.Message = "您结束了当前操作!"
        Me.Close()
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        _WaitTime += TimeSpan
        Me.labTimer.Text = String.Format("{0}秒", _WaitTime / 1000)


        If Not Me._AsyncResult.IsCompleted Then

            If _WaitTime > _MaxWaitTime Then
                _method.EndInvoke(_AsyncResult)
                Message &= String.Format("处理数据超时{0}秒,结束当前操作!", _MaxWaitTime / 1000)

                Me.Close()
            End If
        Else
            Me.Message = String.Empty
            Me.Close()
        End If
    End Sub

    Private Sub LoadForm_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        _AsyncResult = _method.BeginInvoke(Nothing, Nothing)
    End Sub

End Class

再到主窗体MainForm里添加调用等待窗体的代码:

Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
        Dim f As LoadForm = New LoadForm(Sub()
                                             Threading.Thread.Sleep(9000)
                                             MessageBox.Show("OK")
                                         End Sub, 5, "Plase Wait...", True, True)
        f.ShowDialog(Me)
        Dim Res As String = f.Message
        If Not String.IsNullOrEmpty(Res) Then
            MessageBox.Show(Res)
        End If
        f.Dispose()
    End Sub

代码的关键处是用到了委托机制,而且最关键是异步调用委托(BeginInvoke和EndInvoke),为了方便,这里使用.Net Framework中提供的预定义委托MethodInvoker,内置的委托还有Action、Func、Predicate等。用到委托的时候建议尽量使用这些委托类型,而不是在代码中定义更多的委托类型。这样既可以减少系统中的类型数目,又可以简化代码。
关联委托方法时使用了Lambda 表达式,其实就是一个没有方法名的方法,可以有返回值。
遗憾的是,测试时发现点击取消时仅是关闭了等待窗体,但并没有关闭长时间操作的代码,即 _method委托关联的方法还在后台运行,这好像有点不妥,但异步委托只有调用方法和侦测方法是否运行结束,并没有提供中途中止代码运行的办法,该如何处理呢?
有关委托的相关知识请参阅:
1、初识委托——System.Delegate 类
2、官方帮助《使用异步方式调用同步方法》
3、官方帮助《委托 (Visual Basic)》
本文参加了以下博文:
1、Winform等待窗口的实现(附源代码)
2、Tzhtec.Controls组件库(三)TzhtecWaitBar

相关资源可以到下载频道下载:https://download.csdn.net/user/zyjq52uys/uploads

你可能感兴趣的:(VB.NET学习笔记)