在VB.Net WinForms应用程序中使用加载进度更新启动画面

Since .Net 2.0, Visual Basic has made it easy to create a splash screen and set it via the "Splash Screen" drop down in the Project Properties.  A splash screen set in this manner is automatically created, displayed and closed by the framework itself.  The default minimum display time is two seconds, and the splash will stay open longer if necessary until the main form has completely loaded.  All of this is well documented on MSDN, commonly known, and discussed pretty extensively in tutorials easily found on the internet.

从.Net 2.0开始,Visual Basic使得创建启动画面并通过项目属性中的“启动画面”下拉菜单变得容易。 以这种方式设置的启动屏幕由框架本身自动创建,显示和关闭。 默认的最小显示时间是两秒钟,如果需要,在主窗体完全加载之前,启动画面将保持打开状态的时间更长。 所有这些在MSDN上都有很好的记录,众所周知,并且在Internet上容易找到的教程中对此进行了广泛的讨论。

The "Splash Screen" Setting in Project Properties:

项目属性中的“启动画面”设置:

Splash Screen set via Project --> Properties

What isn't commonly found, though, are good examples of how to update the splash screen with progress information from the main form as it loads.  Many examples and tutorials simply use a static splash screen and leave it at that.  MSDN provides an example of how to "update the splash screen with status information" in the MSDN documentation of: My.Application.SplashScreen() property.

但是,通常找不到的很好的示例是如何在加载初始窗体时使用来自主窗体的进度信息来更新初始屏幕。 许多示例和教程仅使用静态启动画面,然后将其保留。 MSDN在My.Application.SplashScree的MSDN文档中提供了一个如何n()属性

In that example, the code is being run from the Application.Startup() event, and changes to the splash screen are done in a direct manner:

在该示例中,代码是从Application.Startup()事件运行的,并且对初始屏幕的更改以直接的方式完成:

Private Sub MyApplication_Startup(ByVal sender As Object, ByVal e As Microsoft.VisualBasic.ApplicationServices.StartupEventArgs) Handles Me.Startup
    ' Get the splash screen.
    Dim splash As SplashScreen1 = CType(My.Application.SplashScreen, SplashScreen1)
    ' Display current status information.
    splash.Status = "Current user: " & My.User.Name
End Sub

小心! 提前多线程...
(Careful!  Multi-threading ahead...
)

The code is misleading because it implies that we can do this from anywhere.  What isn't well documented or being made clear is that the splash screen and the main form of an application actually run in two different threads.  Attempts to use similar code from the Load() event of your main form will result in varying degrees of success depending upon your version of Visual Studio.  The code does demonstrate that "My.Application.SplashScreen" can be used to obtain a reference to the instance of the splash screen displayed automatically by the framework.  Well use that little nugget later...

该代码具有误导性,因为它暗示我们可以在任何地方进行此操作。 没有充分记录或弄清楚的是, 启动屏幕和应用程序的主要形式实际上在两个不同的线程中运行。 尝试使用主窗体的Load()事件中的类似代码将导致不同程度的成功,具体取决于您的Visual Studio版本。 该代码确实演示了“ My.Application.SplashScre en”可用于获取框架自动显示的初始屏幕实例的引用。请稍后使用该小块...

Since the splash screen and the main form are in two different threads, the correct approach to communicating between them is to use the Invoke() method with a delegate.  This is covered in the MSDN article, How to: Make Thread-Safe Calls to Windows Forms Controls.

由于初始屏幕和主窗体位于两个不同的线程中,因此在它们之间进行通信的正确方法是将Invoke()方法与委托一起使用。 MSDN文章“ 如何:对Windows窗体控件进行线程安全的调用”中对此进行了介绍。

Many don't even think to use this approach, though, since cross-thread communication is not normally an issue when dealing with two forms.  The splash screen, then, is an exception to the rule!

但是,许多人甚至都不考虑使用这种方法,因为在处理两种形式时,跨线程通信通常不是问题。 初始屏幕是规则的例外!

The pattern outlined in the article above is as follows:

上面的文章中概述的模式如下:

Delegate Sub SetTextCallback([text] As String)

Private Sub SetText(ByVal [text] As String)
    If Me.textBox1.InvokeRequired Then
        Dim d As New SetTextCallback(AddressOf SetText)
        Me.Invoke(d, New Object() {[text]})
    Else
        Me.textBox1.Text = [text]
    End If
End Sub

We use InvokeRequired() to determine if the calling thread is different from the thread that created the control.  If yes, then we create an instance of the delegate that points to the same exact method.  Next we use Invoke() to run the delegate on the thread that created the control and pass the parameters using an array of Object.  This actually results in a recursive call since the delegate points to the same method.  On the second run InvokeRequired() will return false and the Else block will execute where the control can be safely updated.

我们使用InvokeRequired()确定调用线程是否与创建控件的线程不同。 如果是,那么我们将创建一个指向相同精确方法的委托实例。 接下来,我们使用Invoke()在创建控件的线程上运行委托,并使用Object数组传递参数。 由于委托指向相同的方法,因此实际上会导致递归调用。 在第二次运行时,InvokeRequired()将返回false,并在可以安全更新控件的位置执行Else块。

So let's apply the same pattern to a splash screen.  Below is a simple setup consisting of a Borderless Form with a BackgroundImage, Label and a ProgressBar:

因此,让我们将相同的模式应用于初始屏幕。 下面是一个简单的设置,该设置由无边距窗体以及BackgroundImage,Label和ProgressBar组成:

Splash Screen Form Setup

Here is the code for frmSplashScreen:

这是frmSplashScreen的代码:

Public Class frmSplashScreen

    Private Delegate Sub UpdateProgressDelegate(ByVal msg As String, ByVal percentage As Integer)

    Public Sub UpdateProgress(ByVal msg As String, ByVal percentage As Integer)
        If Me.InvokeRequired Then
            Me.Invoke(New UpdateProgressDelegate(AddressOf UpdateProgress), New Object() {msg, percentage})
        Else
            Me.Label1.Text = msg
            If percentage >= Me.ProgressBar1.Minimum AndAlso percentage <= Me.ProgressBar1.Maximum Then
                Me.ProgressBar1.Value = percentage
            End If
        End If
    End Sub

    Private Sub frmSplashScreen_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint
        ' Draw a Black Border around the Borderless Form:
        Dim rc As New Rectangle(0, 0, Me.ClientRectangle.Width - 1, Me.ClientRectangle.Height - 1)
        e.Graphics.DrawRectangle(Pens.Black, rc)
    End Sub

End Class

Note that I'm using "Me" instead of a control name to check for InvokeRequired().  The "Me" in this case represents the Form itself and is valid since Forms also Inherit from Control.  All controls run in the same thread as the form that contains them so this is a clean and safe method of checking.  Also note that in the Else block I am updating both the Label and the ProgressBar at the same time.  You don't need a separate method with an accompanying delegate for every control; just check against the form and update all controls at once.  The delegate being used receives both parameters and the Object array contains both parameters passed to the method.

请注意,我使用的是“ Me”而不是控件名称来检查InvokeRequired()。 在这种情况下,“我”代表表单本身,并且由于表单也从控件继承而有效。 所有控件都与包含它们的窗体在同一线程中运行,因此这是一种干净安全的检查方法。 还要注意,在其他块中,我同时更新了Label和ProgressBar。 您无需为每个控件都提供带有委托的单独方法。 只需对照表格检查并立即更新所有控件。 使用的委托接收两个参数,并且Object数组包含传递给方法的两个参数。

With that code in place, all the main form has to do is call the UpdateProgress() method and the splash screen will take care of the rest.  Remember, a reference to the splash screen instance can be obtained with "My.Application.SplashScreen".  So here is an example Load() event for a main form that updates the splash screen with made up statuses:

有了该代码之后,所有主要形式要做的就是调用UpdateProgress()方法,初始屏幕将处理其余的工作。 请记住,可以通过“ My.Application.SplashScre获取对初始屏幕实例的引用。 因此,这是一个主窗体的示例Load()事件,该事件用已更新的状态更新初始屏幕:

Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim splash As frmSplashScreen = CType(My.Application.SplashScreen, frmSplashScreen)
        Dim MadeUpSteps() As String = {"Initializing...", "Authenticating...", "Retrieving Widgets...", "Loading Components...", "Updating Doomahickies..."}

        For i As Integer = 0 To MadeUpSteps.Length - 1
            splash.UpdateProgress(MadeUpSteps(i), CInt((i + 1) / MadeUpSteps.Length * 100))
            System.Threading.Thread.Sleep(1500)
        Next
    End Sub

End Class

The Splash Screen in Action!

初始屏幕动起来!

Idle-Mind-346085.flv 空闲心理346085.flv

This article hasn't really introduced anything new or mind blowing...it just puts two and two together to accomplish something that really should be much simpler!

本文并没有真正介绍任何新东西或令人发指的东西……它只是将两个和两个放在一起来完成实际上应该更简单的事情!

翻译自: https://www.experts-exchange.com/articles/3671/Updating-a-Splash-Screen-with-Loading-Progress-in-a-VB-Net-WinForms-Application.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值