在.NET 4.0中我正在处理一个加载时间很长(大约20秒)的应用程序,所以我想在一个表单上显示一个swish滚动选框,它在加载时会出现在应用程序的顶部。
由于主UI线程正在进行数据UI元素的所有加载,因此我无法在单独的线程上执行该操作,因此我最终尝试在新线程上运行该表单。我最终在表单中坚持使用这个代码,让它显示在一个新的线程上,如下所示:
Public Class frmWait
Public Property Message As String
Get
Return Me.lblMessage.Text
End Get
Set(value As String)
If Not String.IsNullOrEmpty(value) Then
Me.lblMessage.Text = value
Else
Me.lblMessage.Text = DefaultMessage
End If
End Set
End Property
Private OwnerThread As Thread
Private OwnerForm As Form
Private Const DefaultMessage As String = "しばらくお待ちください..."
Public Sub New(ByVal ParentForm As Form)
InitializeComponent()
Me.Message = DefaultMessage
Me.OwnerForm = ParentForm
End Sub
Public Sub New(ByVal Message As String, ByVal ParentForm As Form)
Call InitializeComponent()
Me.Message = Message
Me.OwnerForm = ParentForm
End Sub
Public Sub ShowOnThread()
' Position the form in the center of the owner
With Me.OwnerForm
Dim ownerCenter As New Point(.Location.X + CInt(.Width / 2), .Location.Y + CInt(.Height / 2))
Me.Location = New Point(ownerCenter.X - CInt(Me.Width / 2), ownerCenter.Y - CInt(Me.Height / 2))
End With
Me.OwnerThread = New Thread(New ThreadStart(AddressOf Me.ShowDialog))
Call Me.OwnerThread.Start()
End Sub
Public Shadows Sub Close()
If Me.OwnerThread IsNot Nothing AndAlso Me.OwnerThread.IsAlive Then
Call Me.OwnerThread.Abort()
Else
Call MyBase.Close()
End If
End Sub
End Class
这可能非常笨拙,但我在应用程序的不同位置显示它,所以这似乎是最有效的代码方式...
它实际上运作得很好,但我不时会遇到问题,需要一些帮助才能解决这些问题。
有时当表单关闭时,我会收到有关线程以不安全的方式中止的错误。
目前我将表单手动放置在表单中心,我希望它覆盖表单。理想情况下,我希望能够在其上调用.ShowDialog(ParentForm)
,但当然由于从一种形式到另一种形式的跨线程访问而引发异常。
任何有关如何解决此问题的建议都将非常受欢迎。 因为我对线程几乎一无所知,所以我可能把它编成像猴子一样,所以如果有更好的方法来完成它,我非常想知道它。
我列出的代码是在VB.NET中,但是C#中的答案代码也很好(对于任何过分热心的重复者)
更新:
我现在意识到我应该在我的问题中提供更多细节......等待表单实际上不是我显示应用程序的第一种形式。首先是登录屏幕。当用户通过身份验证时,登录表单将启动应用程序的主界面,这是实际需要很长时间才能加载的表单。
我在登录表单和主界面之间显示等待表单。我还使用此表单来覆盖用户在主界面上启动的任何长时间运行的任务。
答案 0 :(得分:1)
您应该将加载代码移动到单独的线程/后台工作程序,而不是尝试在单独的线程上显示对话框。
然后只需启动线程并在form_load上显示进度条并在线程完成时隐藏进度条:
Dim _progressForm As frmLoading
Private Sub frmMain_Load(sender As System.Object, e As System.EventArgs) Handles Me.Load
'start loading on a separate thread
BackgroundWorker1.RunWorkerAsync()
'show a marquee animation while loading
_progressForm = New frmLoading
_progressForm.ShowDialog(Me)
End Sub
Private Sub BackgroundWorker1_DoWork(sender As System.Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker1.DoWork
'simulate a long load
For i As Integer = 1 To 10
System.Threading.Thread.Sleep(1000)
Next
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As System.ComponentModel.RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
_progressForm.Close()
End Sub
答案 1 :(得分:1)
VisualStudio可以为您完成此操作。当然,您当然可以自己编写,但如果您查看Application
下的项目选项,则会设置Splash Screen
。您可以将任何表单(启动表单除外)指定为启动画面。它在自己的线程上运行,您可以在启动期间对其进行调整以推进进度条等。
答案 2 :(得分:0)
看一下TaskFactory.New
运行不同线程的线程代码以保持UI响应
http://msdn.microsoft.com/en-us/library/ee782519.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-3
答案 3 :(得分:0)
您可以使用ApplicationContext
类来允许首先运行启动画面,然后在准备好时在主窗体中交换。在Application.Run的调用中使用它代替主窗体:
Application.Run(new MyApplicationCtx())
也为你搜索了一篇文章:
http://www.codeproject.com/Articles/5756/Use-the-ApplicationContext-Class-to-Fully-Encapsul