【问题标题】:Something wrong with Marquee progress bar选取框进度条有问题
【发布时间】:2015-09-30 03:03:00
【问题描述】:

我正在学习使用线程并制作一些多线程演示。

我有一个名为 lblText 的标签和一个名为 pgbRun 的选框进度条。我做了2个线程,一个让标签的文本在每个Thread.Sleep()被调用后改变,另一个让进度条在标签的文本改变时显示动画。

我遇到的问题是文本更改线程似乎运行良好,但进度条线程有问题。 pgbRun 只是在文本更改完成后开始制作动画。

请帮我找出我的代码有什么问题,并告诉我一些修复它的方法。非常感谢!

private delegate void formDelegate();

private void btnRun_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(new formDelegate(textChange)));
    thread.IsBackground = true;
    thread.Start();
}

public void textChange()
{
    if (lblText.InvokeRequired)
    {
        lblText.BeginInvoke(new formDelegate(textChange));
    }
    else
    {
        Thread thread = new Thread(new ThreadStart(new formDelegate(progess))); 
        thread.IsBackground = true;
        thread.Start();

        //I try make single thread that config progress bar here but i have same trouble.

        for (int i = 0; i < 10; i++)
        {
            lblText.Text = "Count: " + i;
            lblText.Update();
            lblText.Refresh();
            Thread.Sleep(300);
        }
    }
}

public void progess()
{
    if (pgbRun.InvokeRequired)
    {
        pgbRun.BeginInvoke(new formDelegate(progess));
    }
    else
    {
        pgbRun.Style = ProgressBarStyle.Marquee;
        pgbRun.MarqueeAnimationSpeed = 20;
        pgbRun.Update();
        pgbRun.Refresh();
    }
}

【问题讨论】:

  • 您的线程不会做任何有用的事情,它们会立即调用 UI 线程。 textChange() 代码没有完成更多工作,但会导致 UI 挂起 3 秒。您可以看到标签更改,因为您调用了 Update()。 progess() 中的 BeginInvoke() 调用被卡住了 3 秒钟,因为 UI 线程正忙于睡眠,因此您看不到进度条发生任何事情。你需要把这段代码扔掉。
  • @HansPassant 那么我该如何解决呢?

标签: c# multithreading winforms progress-bar marquee


【解决方案1】:

阅读this very useful article 后,我发现#Hans 是如此真实。我的第一个代码是垃圾,所以我编辑我的代码如下。进度条的基本属性在设计器中设置,在代码中我只是更改可见选项。

delegate void textChangeDelegate(int x);

private void btnRun_Click(object sender, EventArgs e)
{
    Thread thread = new Thread(new ThreadStart(new MethodInvoker(threadJob)));
    thread.IsBackground = true;
    thread.Start();
}

public void threadJob()
{
    Invoke(new MethodInvoker(show));
    for (int i = 0; i < 10; i++)
    {
        Invoke(new textChangeDelegate(textChange),new object[]{i});
        Thread.Sleep(500);
    }
    Invoke(new MethodInvoker(hide));
}

public void textChange(int x)
{
    if (InvokeRequired)
    {
        BeginInvoke(new textChangeDelegate(textChange),new object[] {x});
        return;
    }
    x += 1;
    lblText.Text = "Count: " + x;
}

public void show()
{
    pgbRun.Visible = true;
    lblText.Visible = true;
}

public void hide()
{
    pgbRun.Visible = false;
    lblText.Text = "";
    lblText.Visible = false;
}

【讨论】:

    【解决方案2】:

    您应该为此使用 Microsoft 的响应式框架。这会让事情变得容易得多。

    代码如下:

    private void btnRun_Click(object sender, EventArgs e)
    {
        Observable
            .Interval(TimeSpan.FromMilliseconds(300.0))
            .Take(10)
            .Select(n => String.Format("Count: {0}", n))
            .ObserveOn(this)
            .Subscribe(t => lbl.Text = t);
    }
    

    就是这样。

    只需 NuGet "Rx-WinForms" 并将其添加到您的项目中。

    不清楚您要对进度条做什么。您能否提供更多详细信息?

    【讨论】:

    • 感谢您的回答。我正在尝试用两个线程创建一个多线程演示。一个更改标签的文本,另一个在这些文本充电时“打开”进度条。我真的很感谢你提供了这么好的框架,但我需要解决线程和多线程问题。所以你的解决方案将来应该对我有用。
    • @tungns304 - 这是多线程。它只是使用一个为您管理线程的框架。 ObserveOn(this) 之前的一切都发生在后台线程上,然后又回到 UI 线程上。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-13
    相关资源
    最近更新 更多