【问题标题】:Availability of windows form during processing处理期间窗口窗体的可用性
【发布时间】:2010-01-27 17:30:53
【问题描述】:

我正在做一个执行某种扫描的应用程序(它通过一个短列表检查 URL 的可用性),并根据结果,它添加到一个或另一个列表框。如果存在,则转到 lstOK,否则,转到 lst404。

问题是这些网络检查需要时间(特别是在正常的情况下),需要很长时间,并且最后将所有项目插入到列表框中,而表单“没有响应”并且什么都没有出现或者可以点击或显示任何交互。

有没有办法让表单仍然可用并且列表框可以随时更新?

这应该很简单,我只是不知道(还)

我在 Visual Studio 中使用 C#

--[更新]--
整个 url 检查都在一个函数 Start() 中

【问题讨论】:

  • 这是 Web 应用还是 WinForm 应用?
  • @Tim:问题的标题是处理过程中windows窗体的可用性
  • 是的,但是“有没有办法让网络表单仍然可用并且列表框可以随时更新?”让我想知道您是否在使用网络应用程序。
  • 好的,没看到(我阅读问题过快的习惯再次发作)。我知道你的问题是从哪里来的。在我看来仍然像 Windows 窗体(例如“没有响应”)

标签: c# visual-studio winforms multithreading


【解决方案1】:

【讨论】:

    【解决方案2】:

    如果这是执行这些“网络检查”的桌面应用程序,那么您可以使用 BackgroundWorkerThread 来执行处理并获取结果。

    或者你可以这样做:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    using System.Threading;
    
    namespace ThreadWithDataReturnExample
    {
        public partial class Form1 : Form
        {
            private Thread thread1 = null;
    
            public Form1()
            {
                InitializeComponent();
    
                thread1 = new Thread(new ThreadStart(this.threadEntryPoint));
                Thread1Completed += new AsyncCompletedEventHandler(thread1_Thread1Completed);
            }
    
            private void startButton_Click(object sender, EventArgs e)
            {
                thread1.Start();
                //Alternatively, you could pass some object
                //in such as Start(someObject);
                //With apprioriate locking, or protocol where
                //no other threads access the object until
                //an event signals when the thread is complete,
                //any other class with a reference to the object 
                //would be able to access that data.
                //But instead, I'm going to use AsyncCompletedEventArgs 
                //in an event that signals completion
            }
    
            void thread1_Thread1Completed(object sender, AsyncCompletedEventArgs e)
            {
                if (this.InvokeRequired)
                {//marshal the call if we are not on the GUI thread                
                    BeginInvoke(new AsyncCompletedEventHandler(thread1_Thread1Completed),
                      new object[] { sender, e });
                }
                else
                {
                    //display error if error occurred
                    //if no error occurred, process data
                    if (e.Error == null)
                    {//then success
    
                        MessageBox.Show("Worker thread completed successfully");
                        DataYouWantToReturn someData = e.UserState as DataYouWantToReturn;
                        MessageBox.Show("Your data my lord: " + someData.someProperty);
    
                    }
                    else//error
                    {
                        MessageBox.Show("The following error occurred:" + Environment.NewLine + e.Error.ToString());
                    }
                }
            }
    
            #region I would actually move all of this into it's own class
                private void threadEntryPoint()
                {
                    //do a bunch of stuff
    
                    //when you are done:
                    //initialize object with data that you want to return
                    DataYouWantToReturn dataYouWantToReturn = new DataYouWantToReturn();
                    dataYouWantToReturn.someProperty = "more data";
    
                    //signal completion by firing an event
                    OnThread1Completed(new AsyncCompletedEventArgs(null, false, dataYouWantToReturn));
                }
    
                /// <summary>
                /// Occurs when processing has finished or an error occurred.
                /// </summary>
                public event AsyncCompletedEventHandler Thread1Completed;
                protected virtual void OnThread1Completed(AsyncCompletedEventArgs e)
                {
                    //copy locally
                    AsyncCompletedEventHandler handler = Thread1Completed;
                    if (handler != null)
                    {
                        handler(this, e);
                    }
                }
            #endregion
    
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果是 Web 表单,请查看 AJAX.NET。有几个控件(UpdatePanel 是我脑海中的一个)可以帮助您做到这一点。

      看看toolkit

      编辑:仅适用于网络应用。

      【讨论】:

        【解决方案4】:

        Application.DoEvents();将完成到目前为止发生的所有事件。 例如,在您的循环中,在检查每个网站之后。做应用程序.DoEvents(); 另一方面,如果您只想刷新列表框,则为 listboxname.Refresh();
        但是,这两个选项仍然会有一段时间在网站被 ping 时冻结,除非您执行其中许多选项,我不建议这样做。
        这两种方法也只使用一个线程并且非常线性。
        最好的选择是创建一个新线程来进行测试,或者使用可以在单独的线程上进行测试的后台工作人员,以便可以立即处理表单的事件而无需等待。

        手动控制另一个线程应该不会太困难。 这是一个例子。

        using System.Threading;
        
        public class MultiThreadingClass
        {
            private void FunctionForNewThread()
            {
            //do stuff
            }
        
            private void FunctionWithParameter(object param)
            {
            //Should do checks with typeof() on param before casting
            int convertedparam = (int)param;
            //do stuff
            }
            Thread t, t2;
            static void Main()
            {
                ThreadStart ts = new ThreadStart(FunctionForNewThread);
                t = new Thread(ts);
                t.Start();
                int x = 5;
                ParameterizedThreadStart pts = new ParameterizedThreadStart(FunctionWithParameter);
                t2 = new Thread(pts);
                t2.Start(x);
            }
        }
        

        在此需要注意的是,您永远不应该将线程添加为会消失的局部变量,因为您只能通过在新线程调用的函数中执行 Thread.CurrentThread 来真正取回线程实例,但是如果那个线程已经被锁定了,那你就有点问题了:)

        要轻松处理全局变量中的线程,请创建线程数组并调用 Thread.Abort();在程序关闭时在每个正在运行的线程上,或使用 System.Threading 中的 ThreadPool 类。

        【讨论】:

        • Application.DoEvents() 应该避免。使用后台工作者,这就是它的设计目的。
        • 我确实涵盖了许多方面,包括后台工作者和多线程。我同意 Application.DoEvents() 是一个非常糟糕的选择,我只是涵盖了所有选项。这就是为什么我在回答中说最好的选择是另一个线程或后台工作人员。请不要不必要地投反对票。
        • 支持你。我目前没有时间做这件事(我不认为创建另一个线程会如此广泛)所以我已经把它改为让我使用这个个人应用程序,直到我有时间做出最终解决方案。谢谢你。注意:永远不要对某人投反对票,因为这不是最好的答案,只有在它错了并且会让提问者失去时间时才投反对票。谢谢你,skintkingle。
        • 我已经通过手动使用线程的示例编辑了我的答案,我希望它能对您的线程创建问题有所帮助。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-05-31
        • 2010-12-14
        • 2011-01-20
        相关资源
        最近更新 更多