【问题标题】:Progress bar until long process进度条直到漫长的过程
【发布时间】:2014-12-29 12:52:50
【问题描述】:

我在 .NET 3.5 中有程序(winform),它可以将文件发送到 ftp 服务器。我想要进度条,我尝试在后台使用线程,但我有错误。

这是我的代码示例:

private void Odeslat_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(Process);
    thread.IsBackground = true;
    thread.Start();        
}

public void Process()
{
    button1.Enabled = false;
    button2.Enabled = false;

    foreach (string Prodejna in SeznamProdejen)
    {
        i = i + 1;
        Update1(i);

        //some long task
    }
}

public void Update1(int i)
{
    if (InvokeRequired)
    {
        this.BeginInvoke(new Action<int>(Update1), new object[] { i });
        return;
    }

    progressBar1.Value = i;
 }

这里有错误:

button1.Enabled = false;

这个错误:

{"Operation between threads is not valid: Access to the control button1 took place from another thread than the thread under which it was created."}

在公共无效进程中,我有一个程序,它将文件发送到 ftp 服务器。

!!!!!!但是现在我有问题,这是我的代码示例:!!!!!!

private void Odeslat_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button2.Enabled = false;

            Thread thread = new Thread(Process);
            thread.IsBackground = true;
            thread.Start();  

            MessageBox.Show("Výsledek odesílání naleznete v souboru vysledek.txt", "Výsledek");
            button1.Enabled = true;
            button2.Enabled = true;
        }

public void Process()
        {
        foreach (string Prodejna in SeznamProdejen)
                {
            i = i + 1;
                        Update1(i);

            //some long task

                        ..............
                        Stream reqStream = request.GetRequestStream();   //PROBLEM
                                reqStream.Write(buffer, 0, buffer.Length);
                                reqStream.Close();
                        .................
        }
    }

public void Update1(int i)
        {
            if (InvokeRequired)
            {
                this.BeginInvoke(new Action<int>(Update1), new object[] { i });
                return;
            }

            progressBar1.Value = i;
        }

问题:程序何时靠近 Stream reqStream = request.GetRequestStream();跳转到私有 void Odeslat_Click 到 messagebox.show。在那之后……我不明白为什么?

【问题讨论】:

  • 这个 wpf 是什么样的项目?赢形式?其他的?
  • 试试Dispatcher.Invoke(new MethodInvoker(delegate{button1.Enabled = false;}));而不是button1.Enabled = false;
  • 我的程序必须在 .NET Framework 3.5 中...这个 .Net 没有 Dispatcher :/
  • 您是否希望在线程结束时重新启用按钮?

标签: c# multithreading progress-bar


【解决方案1】:

您正在从另一个线程中访问控件(button1button2),而不是创建它们的主线程。所以正如消息所说,这是无效的。

一种选择是在生成新线程之前简单地禁用按钮:

private void Odeslat_Click(object sender, EventArgs e)
{
    button1.Enabled = false;
    button2.Enabled = false;

    Thread thread = new Thread(Process);
    thread.IsBackground = true;
    thread.Start();        
}

【讨论】:

    【解决方案2】:

    在您的设计器中添加一个计时器(在我的示例中为计时器 1),将计时器设置为根据需要经常检查。将时间间隔设置为适合您的时间间隔(1 秒检查设置为 1000)。

    bool progress = false;
    private void Odeslat_Click(object sender, EventArgs e)
    {
        progress = true;
        timer1.Start();
        Thread thread = new Thread(Process);
        thread.IsBackground = true;
        thread.Start();        
    }
    
    private void timer1_Tick(object sender, EventArgs e)
    {
        if(!progress)
        {
            button1.Enabled = true;
            button2.Enabled = true;
            timer1.Stop();
        }else
        {
            button1.Enabled = false;
            button2.Enabled = false;
        }
    }
    
    public void Process()
    {
        foreach (string Prodejna in SeznamProdejen)
        {
            i = i + 1;
            Update1(i);
    
           //some long task
        }
        progress = false;
    }
    

    【讨论】:

    • 我认为不需要计时器。当 foreach 循环运行时,进度条可以增加。此外,您代码中的计时器将永远不会停止:/
    • 我自然而然地认为他们在另一个线程中所做的最后一件事是将进度设置为 false 的操作部分有一些意义。这与进度条没有任何关系它控制按钮为什么使用另一个线程计时器在主线程上所以它只是不断检查
    【解决方案3】:

    您可以通过调用后台线程来访问控件。

    见:Control.Invoke()http://msdn.microsoft.com/de-de/library/zyzhdc6b(v=vs.110).aspx

    所以在你的情况下,就可以这样做:

    this.Invoke(new Action(() => { 
        button1.Enabled = false; 
        button2.Enabled = false;
    } ));
    

    当然,您也可以定义一个额外的方法来代替使用 lambda 表达式。如果您向该方法添加更多内容以提高可读性,那么建议您这样做。

    【讨论】:

      最近更新 更多