返回首页

正确的进度通知
这是要以极大的怀疑满足,但我会说,无论如何??只有一个最好的方式展现了长时间操作的进度窗口。答案是一个模式进度窗口,同时在UI线程上的工作是做的工作线程上显示。
首先,让我们来看看为什么进度窗口必须在UI线程上:如果您尝试一个工作线程上显示一个对话框,该对话框不能从调用线程的所有者。尝试,你会得到异常:

Cross-thread operation not valid: Control 'Form1' accessed from a thread 

other than the thread it was created on.

和显示在另一个线程中的对话框没有所有者(模态或非)出现对话框非模态,因此允许用户点击你的主窗口和宽松的进度窗口的Z -顺序决策的深处为用户很难知道如果操作仍在进行中或没有。
一招,你可能会尝试设置进度窗口的TopMost属性,迫使它在上面。不幸的是,这使所有其他窗口的顶部,而不是理想的用户尝试多任务,而他们等待您的应用程序做它的事。
接下来,让我们来看看为什么应该在一个单独的线程完成所有工作。如果你不和的应用程序不调用的DoEvents,应用程序将很快成为无响应尽可能Windows的关注,用户将看到在标题栏的消息"没有响应??如果用户尝试一下就可以了。而我们都知道,用户觉得有权告诉你,你的应用程序"冻结??或"挂起??当他们看到这。
那么为什么不利用的DoEvents,让您的应用程序回应?你不仅需要调用频繁的DoEvents给响应的应用程​​序的外观,但的DoEvents是邪恶的。在您的操作调用的DoEvents使你的代码要少得多可重复使用的。假设你有一个可爱的小程序,是能够排序号码。在这种情况下,您可以锁定用户界面和显示一个进度条,这样的DoEvents似乎完成预期的效果。但想象有人在向导的步骤之间重用您的排序例程。用户点击下一步,代码运行和调用的DoEvents,用户无论出于何种原因,决定再次单击"下一步",程序已完成之前。也许,用户只需双击,因为他们很单击高兴。按钮的Click事件将再次触发,并可能陷入各种麻烦您,因为您的代码将运行两次。应该预计可以重复使用而不用担心再入同步的代码。如果我们所有的承诺,将有较少的错误,在我们的应用程序和我们的代码会更容易重用。这种在我看来细节,根本就不是例行的消费者应该需要担心的东西。
最后,进度对话框模式或无模式?您可能认为这并不重要。假设你的代码,需要运行工作线程完成后,不要紧,如果代码是在一些"线程运行完成??的事件处理程序或后,立即关闭进度窗口呢?在许多情况下,我承认这一点并不重要。但我断言,这是很好的做法,后来做了。这是因为你的代码始终处于某种方式被称为一个事件处理程序。无论是一个按钮单击事件或提高小组主要的例外事件,一些对象,你总是运行在某种事件处理程序。如果你生成辅助线程并立即返回,该事件的调用者可能会遇到一些额外的代码。现在,因为你显示一个进度条,你是表明,没有完成此操作的用户。那么,为什么你会从事件中返回,如果操作没有完成?如果有该事件的多个观察员。有什么能阻止第二个事件处理程序添加到同一事件的另一个模块。而如果你立即返回,代码将运行之前,你长的操作已经完成。这可能不是一个问题,但它可能。它可能会认为,没有一个模式对话框显示的情况下,它需要展现自己,或它可能是依赖于你的代码之前完成它的东西。
此外,事件可能做自己的事情,事后假设你操作。例如,假设一个事件BeforeOpen和另一AfterOpen。如果您在BeforeOpen长时间操作并立即返回,AfterOpen火之前就大功告成了。消费者对这一事件可能假设你不管它是什么,你正在做成品。最后:如果事件呼叫者诱捕例外。等待你的线程来完成也可以让你的陷阱你的线程和泡沫备份事件的发行人,或甚至可能适当EventArgs.Cancel标志的例外。到目前为止,所有这些原因,我断言,这是很好的做法显示为模态进度对话框,除非你有令人信服的理由不。
因此,如何做,我们做了这一切?虽然有不止一种方法,在我看来最容易使用的System.ComponentModel.BackgroundWorker对象。具体方法如下:{C}
瞧!它的那样简单。想必你也报告通过BackgroundWorker对象及其关联的ProgressChanged事件完成一个百分点,但也许你刚刚有进步一点点的重复的动画,而不是在这种情况下,这是所有你需要的。
警告:用户仍可以进入Alt键F4键或单击在上面的进度对话框右上角的红色X,如果它的存在,所以你需要为了防止这种情况。一个简单的方法来解决这个问题,只是取消形成紧密的,除非它是从我们的代码。
Private AllowClose As Boolean = False



Private Sub FormProgress_FormClosing(ByVal sender As Object, _

            ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing

    If e.CloseReason = CloseReason.UserClosing And AllowClose Then

        e.Cancel = True

    End If

End Sub



Public Sub ForceClose()

    AllowClose = True

    Me.Close()

    AllowClose = False

End Sub

只需拨打FormProgress.ForceClose BackgroundWorker的RunWorkerCompleted事件,而不是和你业务。历史三月十一日,2008年:战后初期

回答

评论会员:rasingh1 时间:2011/12/16
本文帮助我的客户想要什么 - 在UI连续状态长达3个小时的进展更新。谢谢您{S0}
评论会员:TimDJones 时间:2011/12/16
您好,
我创建了一个项目在TreeView加载XML文件WinForm中。
现在我想添加一个进度条,要使用后台工作也将显示文件的进展情况,从我的记忆下载到treeview.i。
在我的winform,我有一个TreeView,"浏览"按钮(选择一个文件),文本框(显示所选的文件名)toolStripStatusLabel,toolStripStatusProgressBar。
能否请你帮助了..
评论会员:Izzet凯雷姆Kusmezer 时间:2011/12/16
这是不是"沃拉沃拉?? "whalla?? "wolla??这样的事情。

!?这是"瞧,现在跟着我重复:瞧。如果你不能prononunce它的权利,或不生活在一个讲法语的城市(运气好),我会是一个很好的运动...在这里:"VU - OH - LA??明白了吗?来自法语,字面意思是如虎添翼,揭开神秘面纱,"这里是??现在没有让我疯了以后再在错误的地方使用它的拼写错误,瞧?

但感谢否则大文章。
评论会员:98z28 时间:2011/12/16
我真的做得不到本文三月最好的文章可以作为选择??
评论会员:会员4230074 时间:2011/12/16
显然有很多人不同意你的意见。我个人认为这是一篇好文章。每个有自己的,我猜。

& #160; 贾森



{A}
评论会员:会员1026370 时间:2011/12/16
我现在有一个应用程序后发起一项行动,开辟了一个形式使用一个线程。形式有2个进度条和文本,需要不断的状态更新... ...虽然它的工作原理,似乎是一个使用这种方法的几个问题:

原来的形式刷新(如果用户的推移远离运行的应用程序)冻结
螺纹进步是固定的
我原来的用户界面是MDI父的一部分... ...形式是不是... ...

请问您建议的方法解决这些问题?
评论会员:添日元 时间:2011/12/16
UI必须始终在UI线程上!从来没有在辅助线程...

您是非常正确的!

不这样做简直是... ...一个设计缺陷!
评论会员:添翠怡 时间:2011/12/16
??"这是要以极大的怀疑满足,但我会说,无论如何,有只有一个最好的方式展现了长时间操作的进度窗口的答案是显示一个模式进度窗口,同时在UI线程上的工作是做的工作线程上。"

YEP IM持怀疑态度。那不是一个好主意。
两个更好的替代品,浮现在脑海中。
1。把状态栏上的进度条(见的MS Word节能进展)
2。 A模式对话框出现在任务栏上,如果你失去了它在后面,你可以把它前面。 (见Firefox的下载窗口)

随着模态对话框中,你不得不等待,直到你的应用程序已经完成它是做什么。试想一下,如果你不得不等待,直到下载完成之前,您可以继续浏览网页!
评论会员:ssm6297 时间:2011/12/16
我应该有资格我的发言,并说,如果你有一个操作,用户需要等待,直到完成,这是最好的方式。我绝对同意,如果你需要允许用户继续工作在您的应用程序独立操作在手,将在状态栏或工具栏的进度条 - 或无模式进度 - 不只是适当的而且是必要的的{。 BR}
感谢您提示澄清。

蒂姆松涛
软件建筑师和工程师
评论会员:ssm6297 时间:2011/12/16
GT,把状态栏上的进度条(见的MS Word节能进展)

代码,或是它没有发生
评论会员:卡万沙班 时间:2011/12/16
没关系。我是一个白痴

评论会员:MaxGuernsey 时间:2011/12/16
!喜添我认为你在这里举行的指引是好的。即便如此,你可以通过调用下面的函数从线程代码内解决的第一个问题上的文章(作为所有者的形式):


Public Delegate Function GetHandleCallBack(ByVal f As Form) As IntPtr

 

Public Function GetHandle(ByVal f As Form) As IntPtr

    

    If f.InvokeRequired Then

 

        Dim fn As GetHandleCallBack = New GetHandleCallBack(AddressOf GetHandle)

        Return DirectCast(f.Invoke([fn], New Object() { f }), IntPtr)

 

    End If

 

    Return f.Handle

 

End Function

事实上,你可以通过使用这种功能的模型与整个UI交互

希望它帮助!

JM
评论会员:扬卡万沙班 时间:2011/12/16
您好,

你能提供的例子,然后,我怎么可能成为拥有这种形式,只是在Win32处理其他线程的进步。
的P /调用,将是必要的的。
在此先感谢,

卡万
评论会员:MaxGuernsey 时间:2011/12/16
{A3}],这是推荐的方式从非UI线程更新UI的对象。从本质上讲,它可以让你"元帅"到该线程的命令。我不会建议得到IntPtr和使用它。

...我完全错过了点?

最大根西岛,三
管理成员,六角软件有限责任公司
{A4}
{A5}
评论会员:卡万沙班 时间:2011/12/16
我不是指更新用户界面,但有一个模式对话框有另一个线程窗口作为父

这是很容易做到在Win32。

我想,我就蹦出来的P /调用和玩耍有点。
评论会员:supercat9 时间:2011/12/16
有自己的UI线程所有的UI对象,它提供了什么价值?

最大根西岛,三
管理成员,六角软件有限责任公司
{A4} {A5}
评论会员:Fiwel 时间:2011/12/16
,这将显示一个进度对话框 在scenerios,涉及大量的数据绑定第三方控件,编组调用通常是速度太慢,有时会因为控制不好实现降权的危险。
因此,为了一个应用程序没有出现如冻结时,它实际上是,我会弹出一个对话框,新它自己的消息泵线程所拥有,太显示一个选取框的进度栏和对等。{BR }
我同意你的100%,在适当的UI线程问题方面,我一直在做,只是在WPF。退房我写了一篇文章,演示了一个多线程,延迟加载,在{A8} WPF的TreeView]