
在实际应用中,当遇到长期的计算和分析时,请用户等待,如果未正确处理表单,则表单通常会处于悬浮状态. 在网络,多线程或BackgroundWorker组件中,还有许多方法可以解决此问题. 并且大多数采用Singleton单模方法.
问题:
1. 大多数复杂的操作在后台(另一个线程)中执行,并且主线程创建一个子线程进行操作. 子线程操作期间是否可以弹出弹出提示表单?子线程并等待提示表单自行完成所有操作.
通常的做法是在后台执行工作时将信息发送到主线程UI.
问题1是本文的重点: 线程A(可以是主线程或子线程)创建一个线程B,该线程B包含等待提示形式,然后A向B发送信息. 然后,父线程A线程或主进程忽略A和B.
2. 如果分析过程中有多个子线程,则Singleton单模一个窗口显示等待的提示信息,一个窗口显示不同的提示信息集同时调用2次vb程序,不好,否则提示信息显示会混乱.
为了解决上述疑问,我参考了该论坛和博客园中几位专家的想法,并编写了一个程序,该程序允许多个等待提示形式. 我的水平是有限的. 只是开,希望每个人都教出更好的方法或想法.
参考链接:
通常有两种等待方式: 引用第一个链接的插图:

图1等待模式. 在后台工作完成之前,UI界面不允许操作.
图2.在非等待模式下,可以在完成后台工作之前操作UI界面.
如何处理本文中的问题:
图3,一种简单的方法. 理论上同时调用2次vb程序,即使任务很大,UI任务也会阻塞. 但这可以解决UI空间不足的问题.
图4推荐的做法,您不必每次编写界面来更新UI线程. 在执行复杂任务期间,您将自己处理等待提示消息,并且主UI不必忽略A和B.

如果有多个等待提示形式,将有多个进程生成多个提示形式,并且为了使等待提示形式不妨碍主线程的操作,必须封装等待提示形式.
封装在一个类中,并且表单的操作模式应该在另一个线程中. 同时,等待提示表单允许创建他的线程向他发送提示信息,并在收到信息后等待提示表单显示.
程序的主要内容是:
1. 等待提示形式: FrmMsgWaitingFor
表单具有多种组合模式:
Public Enum eWaitingFormType
Message '只显示提示信息
Progress '只显示进度条 由于进度无法预测,默认设置Stype属性设为Marquee
MessageAndProgress '显示信息和进度条
MessageAndWorking '显示信息和加载
End Enum
2. 类似于工厂的类,可以创建等待提示形式: MsgWaitingFactory
这种工作需要完成:
2.1您可以创建其他等待提示形式.

2.2在另一个线程中创建一个表单并显示它,以便将调用此类的线程(可以是主线程或子线程)与等待提示表单的线程分开.
2.3主线程可以通过此类的实例将信息发送到等待提示表单,也可以通知并关闭等待提示表单.
3. 调用方式:
调用MsgWaitingFactory方法可以是主线程调用或子线程调用: 也就是说,上面提到的A和B调用:
Dim msgWaiter As New MsgWaitingFactory(eWaitingFormType.MessageAndWorking)
msgWaiter.Show()
msgWaiter.SendMsgToWaiter("开始复杂计算分析...")
'......
'复杂计算分析过程中
msgWaiter.SendMsgToWaiter("提示信息...")
'......
msgWaiter.SendMsgToWaiter("处理完毕.")
msgWaiter.Close()
当然,因为FrmMsgWaitingFor具有简单的跨线程安全处理,所以您也可以直接调用此表单:
Dim frm As New FrmMsgWaitingFor(eWaitingFormType.MessageAndWorking,Me)
frm.Show()
frm.SetMessage("working...")
frm.SetMessage("update UI...")
frm.SetMessage("Finish.")
frm.Close()
等待提示表单的设计界面如下:

源代码: MsgWaitingFactory
Imports System.Threading
Public Class MsgWaitingFactory
Private _threadWaiter As Thread
Private _frmWaiter As FrmMsgWaitingFor
Private _eFormType As eWaitingFormType
Private _MyParentForm As Form
'------------------------------------------------------
'Singleton单一模式
'Private Shared ReadOnly objLock As New Object
'Private Shared _curFrm As FrmMsgWaitingFor
'Public Shared ReadOnly Property CurrentWaitingForForm(e As eWaitingFormType) As FrmMsgWaitingFor
' Get
' SyncLock objLock
' If _curFrm Is Nothing Then
' _curFrm = New FrmMsgWaitingFor(e)
' End If
' Return _curFrm
' End SyncLock
' End Get
'End Property
'------------------------------------------------------
Public Sub New(e As eWaitingFormType)
_eFormType = e
End Sub
'------------------------------------------------------
Public Sub New(e As eWaitingFormType, ParentForm As Form)
_eFormType = e
_MyParentForm = ParentForm
End Sub
Public Sub SendMsgToWaiter(msg As String)
If _frmWaiter IsNot Nothing Then _frmWaiter.SetMessage(msg)
End Sub
Public Sub SendMsgToWaiter(msg As String, isTitle As Boolean)
If _frmWaiter IsNot Nothing Then
If isTitle Then
_frmWaiter.SetFormText(msg)
Else
_frmWaiter.SetMessage(msg)
End If
End If
End Sub
Public Sub Show()
If _threadWaiter IsNot Nothing Then
Try
_threadWaiter.Abort()
_threadWaiter = Nothing
Catch ex As ThreadStartException
End Try
End If
'---------------------
_threadWaiter = New Thread(New ThreadStart(Sub()
_frmWaiter = New FrmMsgWaitingFor(_eFormType)
'_frmWaiter.MdiParent = _MyParentForm
Application.Run(_frmWaiter)
End Sub))
'---------------------
_threadWaiter.IsBackground = True
_threadWaiter.SetApartmentState(ApartmentState.STA)
_threadWaiter.Start()
End Sub
Public Sub Close()
'-----------
'If _threadWaiter IsNot Nothing Then
' Try
' 'Application.OpenForms("FrmMsgWaitingFor").Close()跨线程有异常
' 'Application.OpenForms("FrmMsgWaitingFor").Dispose()
' _threadWaiter.Abort() '终止线程,也有异常。
' _threadWaiter.DisableComObjectEagerCleanup()
' Catch ex As ThreadStartException
' End Try
'End If
'--此方法让窗体自动执行在其线程上关闭
If _frmWaiter IsNot Nothing Then
_frmWaiter.SetCloseForm()
End If
End Sub
End Class
源代码: FrmMsgWaitingFor(某些代码涉及水和烟)
Public Class FrmMsgWaitingFor
Protected Delegate Sub SetControlText(ByVal ctr As Control, ByVal s As String)
Public Sub New(e As eWaitingFormType)
InitializeComponent()
Select Case e
Case eWaitingFormType.Message
HideWorkingImg()
Me.ProgressBarMain.Visible = False
Case (eWaitingFormType.Progress)
HideWorkingImg()
Me.LabelMessage.Visible = False
Case eWaitingFormType.MessageAndProgress
HideWorkingImg()
Case eWaitingFormType.MessageAndWorking
Me.ProgressBarMain.Visible = False
End Select
End Sub
Private Sub HideWorkingImg()
Me.PicWorking.Visible = False
Me.PicWorking.Image = Nothing
End Sub
Protected Sub OnSetControlText(ByVal ctr As Control, ByVal s As String)
If ctr.InvokeRequired Then
Dim m As New SetControlText(AddressOf OnSetControlText)
Me.Invoke(m, New Object() {ctr, s})
Else
ctr.Text = s
End If
Application.DoEvents()
End Sub
Public Sub SetFormText(ByVal s As String)
OnSetControlText(Me, s)
End Sub
Public Sub SetMessage(ByVal s As String)
OnSetControlText(Me.LabelMessage, s)
End Sub
Public Sub SetMessage(ByVal format As String, ByVal args() As Object)
SetMessage(String.Format(format, args))
End Sub
Public Sub SetCloseForm()
If Me.InvokeRequired Then
Dim mi As New MethodInvoker(AddressOf SetCloseForm)
Me.Invoke(mi)
Else
Me.Close()
End If
End Sub
End Class
-执行界面:
已准备就绪,但尚未解决以下问题:
1. 由于程序调用: Application.Run(_frmWaiter)是在当前线程上运行标准应用程序消息循环,因此主界面将暂时失去焦点. 应该有一个解决方案. 但是,有可能允许多个程序同时等待提示. 关闭表单后,主界面重新获得焦点.
2. 进度条的Stype未处理: 阻止百分比显示效果.
3. 其他跨线程问题.
4. 如果有人认为: 毕竟,最好在后台执行工作并将信息发送到主线程以更新UI,那么您可能不理解我要表达的内容.
5. 其他扩展名,请等待提示表单在一段时间后自动关闭,然后进行表单控制,美化,位置控制等,例如右下角的提示.
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/tongxinshuyu/article-279622-1.html
无法调动人口占多数的人民力量
打死一些男人更靠谱