2013-03-22 11 views
0

在.NET 4.0中,我处理的是有一个加载时间较长(约20秒)的应用程序,所以我想显示在沙沙声的滚动字幕一个在应用程序加载时显示的表单。运行在一个单独的线程在等待主UI线程形式来完成

由于主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#的答案代码是罚款太(任何过激retaggers)

UPDATE:

我现在意识到,我应该给很多详细资料在我的问题...等待形式实际上不是我显示应用程序的第一种形式。首先是登录屏幕。当用户通过身份验证时,登录表单将启动应用程序的主界面,这是实际需要很长时间才能加载的表单。

我的登录表单,并在主界面显示之间的等待形式。我还使用这种形式来覆盖用户在主界面上启动的任何长时间运行的任务。

+0

使用的ShowDialog作为线程methid是前途未卜。最好写自己的。 Abort()是危险的和不必要的。 – 2013-03-22 09:03:45

+0

@HenkHolterman谢谢,但你会建议,而不是这些?对于'ShowDialog'我成像'Application.Run()'? – 2013-03-22 09:10:31

回答

1

VisualStudio中能为你做到这一点。你当然可以写自己的,当然,但如果你看看你的项目选项Application下有对Splash Screen的设置。您可以将任何表单(启动表单除外)指定为启动屏幕。这是在它自己的线程上运行的,你可以在启动期间调用它来推进进度条等。

MSDN : Splash Screen

+0

如果我可以从应用程序中多次调用splashscreen,那将会非常有趣。那可能吗? – 2013-03-24 23:56:10

+0

我只是给它一个尝试,但不幸的是我无法弄清楚如何得到那个工作。 – 2013-03-25 00:17:42

+0

@yu_ominae - 你能更具体吗?制作一个表单,将其分配为Splash Screen ...什么不起作用?此实现仅在启动窗体完成加载之前运行。你为什么要多次打电话? – 2013-03-25 00:19:31

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 
+0

这并不总是一个选项。启动有时会涉及大量的加载和初始化是必须由UI线程来完成(特别是当UI线程是一个创建对象和控制,一旦程序莫属它必须拥有)的。这是一个特殊情况,其中繁重的工作不是关于后台任务,而是关于设置有时可能是资源密集型接口的东西。 – 2013-03-22 10:40:19

+0

这实际上是我在的情况。我初始化一对夫妇,我加载到标签在我的主要形式和代码,现在我不能在不同的线程初始化的ActiveX控件。 – 2013-03-24 23:41:41