首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >使用调用进行C#线程处理,冻结表单

使用调用进行C#线程处理,冻结表单
EN

Stack Overflow用户
提问于 2013-01-28 19:19:14
回答 6查看 30.1K关注 0票数 6

我试图使用线程,并防止程序冻结,而线程是繁忙的。它应该显示进步(0/1的书写),而不只是显示完成后的结果,同时冻结表单。

在当前的程序中,我试图写到一个文本框,实际上看到的是不断的进展,并且表单不会受到其他线程的任务的影响。

现在,我可以使用invoke写入带有线程的textbox,但它只显示结果(当线程繁忙时表单冻结),表单冻结。

表格图像:

代码语言:javascript
运行
复制
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace MultiThreading
{
public partial class MultiThreading : Form
{
    public MultiThreading()
    {
        InitializeComponent();
    }

    Thread writeOne, writeTwo;

    private void writeText(TextBox textBox, string text)
    {
        if (textBox.InvokeRequired)
        {
            textBox.BeginInvoke((MethodInvoker)delegate()
            {
                for (int i = 0; i < 500; i++)
                {
                    textBox.Text += text;
                }
            });
        }
        else
        {
            for (int i = 0; i < 500; i++)
            {
                textBox.Text += text;
            }
        }
    }
    private void btnWrite1_Click(object sender, EventArgs e)
    {
        writeOne = new Thread(() => writeText(txtOutput1, "0"));
        writeOne.Start();
    }

    private void btnWrite2_Click(object sender, EventArgs e)
    {
        writeTwo = new Thread(() => writeText(txtOutput2, "1"));
        writeTwo.Start();
    }

    private void btnClear1_Click(object sender, EventArgs e)
    {
        txtOutput1.Clear();
    }

    private void btnClear2_Click(object sender, EventArgs e)
    {
        txtOutput2.Clear();
    }

    private void btnWriteBoth_Click(object sender, EventArgs e)
    {
        writeOne = new Thread(() => writeText(txtOutput1, "0"));
        writeTwo = new Thread(() => writeText(txtOutput2, "1"));

        writeOne.Start();
        writeTwo.Start();
    }

    private void btnClearBoth_Click(object sender, EventArgs e)
    {
        txtOutput1.Clear();
        txtOutput2.Clear();
    }
}

}

编辑:

顺便说一句,我对多线程很陌生,我只是尝试编写一个小程序来理解实现这一目的的最佳方法。

我知道我以前的调用并没有提供真正的帮助,因为我仍然没有给表单一个更新的机会,所以它已经实现了。

好的,所以像这样运行一个线程,但是仍然一起运行多个线程,直到线程完成后才会更新表单。

我添加了一个thread.sleep(),以便在编写时可以尝试并清除,以查看是否仍然可以使用该表单。

当写到一个文本框时,我仍然可以在写的时候清除屏幕。

但是一旦我使用了2个线程,在线程完成并给出输出之前,我就不能再使用表单了。

代码语言:javascript
运行
复制
private void writeText(TextBox textBox, string text)
    {
        for (int i = 0; i < 500; i++)
        {
            Invoke(new MethodInvoker(() =>
            {
                textBox.Text += text;
                Thread.Sleep(2);
            }));
        }

    }

(如果我在这一点上完全错了-我不介意阅读一些例子/线程,除了一个后台工作人员之外,我仍在努力寻找最好的方法。)

编辑2:

我减少了写的数量,减少了调用的次数,但是增加了延迟,产生了与常量写入相同的效果,只是减少了负载。

代码语言:javascript
运行
复制
private void writeText(TextBox textBox, string text)
    {
        for (int i = 0; i < 500; i++)
        {
            Invoke(new MethodInvoker(() =>
            {
                textBox.Text += text;
                Thread.Sleep(2);
            }));
        }

    }

编辑3:

Sumeet的示例使用

Application.DoEvents();

(注意s,.DoEvent不工作,可能是:P),同时写入多个字符串&让它们显示进度,而不仅仅是结果。

因此,代码再次更新:)

*使用一个新按钮创建5个线程,将随机数写入两个文本框

代码语言:javascript
运行
复制
private void writeText(TextBox textBox, string text)
    {
        for (int i = 0; i < 57; i++)
        {
            Invoke(new MethodInvoker(() =>
            {
                textBox.Text += text;
                Thread.Sleep(5);
                Application.DoEvents();
            }));
        }

    }
private void btnNewThread_Click(object sender, EventArgs e)
    {
        Random random = new Random();
        int[] randomNumber = new int[5];
        for (int i = 0; i < 5; i++)
        {
            randomNumber[i] = random.Next(2, 9);
            new Thread(() => writeText(txtOutput1, randomNumber[i-1].ToString())).Start();
            new Thread(() => writeText(txtOutput2, randomNumber[i-1].ToString())).Start();
        }
    }
EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2013-01-28 19:40:47

这个解决方案有效!已经检查过了。

问题是,您一直告诉UI线程更改文本,但从不让它有时间显示更新的文本。若要使UI显示已更改的文本,请添加如下所示的Application.DoEvents行:

代码语言:javascript
运行
复制
textBox.Text += text;
Application.DoEvents();

附注::删除If / else循环的Else块,它是多余的,而且正如其他人所指出的,创建这2个线程没有任何用处,因为他们所做的只是将消息发布在UI线程本身上。

票数 7
EN

Stack Overflow用户

发布于 2013-01-28 19:22:39

您仍在执行单线程任务,如果需要,只需在UI线程上重新启动它。

代码语言:javascript
运行
复制
for (int i = 0; i < 500; i++){
    string text = ""+i;
    textBox.BeginInvoke((MethodInvoker)delegate()
            {
                textBox.Text += text;
            });
}
票数 5
EN

Stack Overflow用户

发布于 2013-01-28 19:25:48

问题是您正在启动一个新线程,然后这个新线程除了为UI线程添加一个要处理大量工作的新任务之外,什么也不做。为了保持表单响应性,您需要有时间让UI线程什么也不做,或者至少不要花费大量的时间执行任何一项任务。

为了保持表单响应性,我们需要大量的小BeginInvoke (或Invoke)调用。

代码语言:javascript
运行
复制
private void writeText(TextBox textBox, string text)
{
    for (int i = 0; i < 500; i++)
    {
        Invoke(new MethodInvoker(() =>
        {
            textBox.Text += text;
        }));
    }
}

通过调用大量的小调用,它允许在操作过程中处理诸如画图事件、鼠标移动/单击事件等事件。还请注意,我删除了InvokeRequired调用。我们知道这个方法将从一个非UI线程中调用,所以不需要它。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14569482

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档