在处理过程中窗体的可用性

时间:2010-01-27 17:30:54

标签: c# visual-studio winforms multithreading

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

问题是这些网络检查需要花费时间(特别是当它没问题时),需要花费很长时间,最后在列表框中插入所有项目,而表单“没有响应”并且没有出现任何内容或者可以点击或显示任何互动。

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

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

我在Visual Studio中使用C#

- [更新] -
整个url检查在一个单独的函数Start()

4 个答案:

答案 0 :(得分:4)

答案 1 :(得分:2)

如果这是执行这些“Web检查”的桌面应用程序,则可以使用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

    }
}

答案 2 :(得分:1)

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

查看toolkit

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

答案 3 :(得分:1)

Application.DoEvents();将完成到目前为止发生的所有事件。 所以在你的循环中,例如,在检查每个网站之后。做Application.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添加为一个会消失的局部变量,因为你只能通过在新线程调用的函数中执行Thread.CurrentThread来获得线程实例。 ,但如果该线程已被锁定,那么你有一点问题:)

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