Что-то не так с индикатором выполнения Marquee

Я учусь использовать потоки и делаю демонстрацию многопоточности.

У меня есть метка с именем 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();
    }
}

person tungns    schedule 11.07.2015    source источник
comment
Ваши потоки не делают ничего полезного, они сразу вызывают поток пользовательского интерфейса. Код textChange() не делает ничего большего, но вызывает зависание пользовательского интерфейса на 3 секунды. Вы можете увидеть изменение метки, потому что вы вызываете Update(). Вызов BeginInvoke() в progess() зависает на эти 3 секунды, так как поток пользовательского интерфейса занят спящим режимом, поэтому вы не видите, что что-то происходит с индикатором выполнения. Вам нужно будет выбросить этот код.   -  person Hans Passant    schedule 11.07.2015
comment
@HansPassant, так как я могу это исправить?   -  person tungns    schedule 11.07.2015


Ответы (2)


Для этого вам следует использовать Microsoft Reactive Framework. Это сделает это намного проще.

Вот код:

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" и добавьте это в свой проект.

Было непонятно, что вы пытаетесь сделать с индикатором выполнения. Не могли бы вы предоставить более подробную информацию об этом?

person Enigmativity    schedule 13.07.2015
comment
Спасибо за ваш ответ. Я пытаюсь создать многопоточную демонстрацию с двумя потоками. Один меняет текст метки, а другой включает индикатор выполнения, пока этот текст заряжается. Я очень ценю вас за эту прекрасную структуру, но мне нужно поработать с многопоточностью и многопоточностью. Так что ваше решение должно пригодиться мне в будущем. - person tungns; 13.07.2015
comment
@ tungns304 - это многопоточность. Он просто использует структуру, которая управляет потоками для вас. Все до ObserveOn(this) происходит в фоновом потоке, а затем обратно в потоке пользовательского интерфейса. - person Enigmativity; 13.07.2015

После того, как я прочитал эту очень полезную статью, я понял, что #Ганс так верен . Мой первый код - мусор, поэтому я редактирую свой код, как показано ниже. Основные свойства индикатора выполнения задаются в дизайнере, в коде я просто меняю видимость.

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;
}
person tungns    schedule 13.07.2015