为什么{} while()循环在button_Click()方法的主体中不起作用

时间:2013-05-09 14:35:44

标签: c# winforms

此代码在控制台应用程序中正常工作,但是当我在Windows窗体应用程序中使用它时,它无法正常工作。它永远不会停止,也不会产生任何输出。

我在这样的控制台应用程序中使用它并且它可以工作:

 static void Main(string[] args)
    {
     Console.WriteLine("Enter your boolean query");
        do{
            string query = Console.ReadLine();
            List<int> lst = ProcessQuery(query);
            count = 0;
            if (lst!=null)
            {
                foreach (int a in lst)
                {
                    if (a == 1)
                    {
                        Console.WriteLine(documentContentList[count]);
                    }
                    count++;
                }
            }
            else
            {
                Console.WriteLine("No search result found");
            }

        }  while(1==1);

    }

我尝试在Windows窗体应用程序中的button_click方法上使用上面的代码,但它不起作用。我认为while(1==1)有问题 - 是否有任何等价物?

以下是我为按钮编写的方法:

 private void button6_Click(object sender, EventArgs e)
    {
        if (t == null)
        {
            MessageBox.Show("Click on LoadFile Button,Please.");
            return;
        }
        if (textBox4.Text == "")
        {
            MessageBox.Show("Enter your Boolean Query");
            return;
        }
        listBox1.Items.Clear();
        DateTime dt = DateTime.Now;
        do{
            List<int> lst = t.ProcessQuery(textBox4.Text);
            count = 0;
            if (lst != null)
            {
                foreach (int a in lst)
                {
                    listBox1.Items.Add(t.documentContentList[count]);
                }
                count++;
            }
            else
            {
                listBox1.Items.Add("No Search Result Found");
            }
            label1.Text = "Search = " + listBox1.Items.Count + " items, " + DateTime.Now.Subtract(dt).TotalSeconds + " s";
        } while (1==1);

    }

6 个答案:

答案 0 :(得分:3)

我相信从button_click事件处理程序中删除do while循环将为您完成这项工作。

private void button6_Click(object sender, EventArgs e)
    {
        if (t == null)
        {
            MessageBox.Show("Click on LoadFile Button,Please.");
            return;
        }
        if (textBox4.Text == "")
        {
            MessageBox.Show("Enter your Boolean Query");
            return;
        }
        listBox1.Items.Clear();
        DateTime dt = DateTime.Now;
        //do{
            List<int> lst = t.ProcessQuery(textBox4.Text);
            count = 0;
            if (lst != null)
            {
                foreach (int a in lst)
                {
                    listBox1.Items.Add(t.documentContentList[count]);
                }
                count++;
            }
            else
            {
                listBox1.Items.Add("No Search Result Found");
            }
            label1.Text = "Search = " + listBox1.Items.Count + " items, " + DateTime.Now.Subtract(dt).TotalSeconds + " s";
       // } while (1==1);

    }

控制台应用程序在等待同步以使用

获取用户输入时暂停执行
string query = Console.ReadLine();

当它获得输入时,它会进行必要的计算并打印要打印的内容,然后再次在同一行等待下一次输入。

winform应用程序不能以这种方式工作,它已经有一个处理UI活动的事件循环(KeyPressed等)

简而言之,您不需要处理程序方法中的循环。

答案 1 :(得分:0)

在Windows窗体或WPF中,UI仅由单个线程管理。因此,如果UI在其线程中调用的代码中有无限循环,它将永远阻塞,并且无法继续更新UI。这就是为什么你不会看到任何对话框出现的原因。

相反,你应该在自己的Thread中运行类似这样的代码,或者更容易在BackgroundWorker对象的构造中运行(然后使用DoWork和ProgressChanged事件)。

答案 2 :(得分:0)

在您的控制台示例中,Consol.ReadLine()调用会阻止用户界面和等待输入。通过使用无限循环,您可以有效地允许用户输入任意数量的查询。但是,在基于Forms / WPF的应用程序中,无限循环实际上是一个糟糕的想法,加上应用程序将保持关闭直到关闭,而不是在完成工作后立即关闭(这就是为什么在控制台应用程序中使用无限循环)

这是因为基于表单的应用程序利用专用线程来更新UI。通过阻止此线程,您还可以防止发生任何其他UI更新,从而冻结您的应用程序。根据您要执行的操作,button6_Click事件方法应将此工作卸载到BackgroundWorker(documentation),这允许在另一个线程上执行工作,然后将更新编组到UI线程上。

答案 3 :(得分:0)

我很清楚;在你的控制台应用程序中,你在循环中有一个Console.ReadLine,它使它停止,直到用户输入一个值并点击Return。在表单应用程序中,您不需要do while循环。用户在textBox4中输入一个值,然后单击一个按钮来处理请求。

答案 4 :(得分:0)

在控制台应用程序中,Main是应用程序的入口点。所有程序都具有此功能,当您启动可执行文件时,操作系统会调用它。

一旦被调用,它将像任何其他函数一样执行(从上到下),如果Main返回一个值,它会对操作系统执行,操作系统会终止程序。

为了防止程序在一次运行后退出,通常的做法是使用while循环来确保未到达main函数的末尾(以及return执行)。

Console.ReadLine是一个阻塞函数 - 这意味着它不会让下一行代码执行,直到它完成它所做的任何事情(在这种情况下,读取来自用户)。

因此,您的控制台应用程序会逐行运行,直到获得输入为止。然后它评估它,输出一个字符串并永远重复。

现在,在WinForms应用程序中,对事物的管理方式略有不同。 UI(按钮,表单,文本框等)由主线程处理,这意味着您需要给它时间来更新。通过在按钮单击功能中使用无限循环,您永远不会将控制权返回给主线程并且UI会锁定。

如果您只想让函数多次运行,请删除while循环,每次单击该按钮时代码都会运行。 Winforms将为您处理。

如果它仍然锁定了UI,则代码阻塞的时间太长(在按钮事件中)。

如果是这样,你必须异步(逐位)或将工作卸载到另一个线程进行密集工作。请查看使用backgroundWorkers以确保UI不会冻结,并删除无限循环。

答案 5 :(得分:0)

  1. 在这两个示例中都有无限循环条件 - 因此您的程序永远无法正常退出循环,即使在您可能通过单击它的'x'来关闭控制台表单而退出的控制台应用程序中,即错误..程序应该实现一个逻辑,允许用户正常退出。

  2. 您的第二个示例无法按预期工作的原因是因为永远不允许刷新您的用户界面。然而,放置无限循环以证明它实际上没有卡住或冻结并且它无法刷新用户界面在循环中添加另一个命令,这是一个不好的做法,如下所示:

  3.    :
            listBox1.Items.Add("No Search Result Found");
            }
            label1.Text = "Search = " + listBox1.Items.Count + " items, " + DateTime.Now.Subtract(dt).TotalSeconds + " s";
           Application.DoEvents(); // add that line
        } while (1==1);
    

    Application.DoEvents();停止执行循环并允许图形用户界面线程更新窗口。

    但正如我之前所说 - 这不是开发应用程序的正确方法,更好的方法是简单地删除该循环,如下所示:

    private void button6_Click(object sender, EventArgs e)
        {
            if (t == null)
            {
                MessageBox.Show("Click on LoadFile Button,Please.");
                return;
            }
            if (textBox4.Text == "")
            {
                MessageBox.Show("Enter your Boolean Query");
                return;
            }
            listBox1.Items.Clear();
            DateTime dt = DateTime.Now;
    
            List lst = t.ProcessQuery(textBox4.Text);
            count = 0;
            if (lst != null)
            {
                foreach (int a in lst)
                {
                    listBox1.Items.Add(t.documentContentList[count]);
                }
                count++;
            }
            else
            {
                listBox1.Items.Add("No Search Result Found");
            }
            label1.Text = "Search = " + listBox1.Items.Count + " items, " + DateTime.Now.Subtract(dt).TotalSeconds + " s";
        }
    

    现在,每次单击按钮时,它都会调用您的事件处理程序,并且当事件处理程序退出例程时,用户界面将自动更新。因为您的表单是从System.Windows.Form类派生的,所以在父类中已经为您实现了用户单击“x”之前保持Windows消息泵的指令,即表单中的System.Windows.Form类源于。

    当然,在控制台应用程序中,情况并非如此。