2016-01-20 2 views
1

Я хочу показать текст на ProgressBar, (без вся глупость custom progress bar). Это не сложно сделать и не включает метод OnPaint - как показано на кнопке 1 следующего кода. Однако этот метод блокирует поток пользовательского интерфейса, который равен evil. К сожалению, мой лучший удар по асинхронному подходу заставляет текст мерцать, что очень раздражает.Почему текст моего асинхронного мерцания ProgressBar меняется?

Может ли кто-нибудь показать мне, как обновить текст асинхронно без мерцания?

(Чтобы запустить следующий код, просто вставьте его в новый проект , содержащий форму с 3 кнопками и 3) индикаторы выполнения.

using System; 
using System.Drawing; 
using System.Windows.Forms; 
using System.Threading.Tasks; 
using System.Threading; 

namespace ProgBarTest //change namespace in Program.cs accordingly 
{ 
    public partial class Form1 : Form 
    { 
     public Form1() 
     { 
      InitializeComponent(); 
     } 

     private void button1_Click(object sender, EventArgs e) 
     { 
      //This method will block the main UI thread 
      // (thus freezing the other buttons) 
      StartUpdate(this.progressBar1); 
     } 
     private void button2_Click(object sender, EventArgs e) 
     { 
      //this method (and the next) don't block the UI, and can be used concurrently, 
      // but the text flickers 
      Task t = new Task(() => StartUpdate(this.progressBar2)); 
      t.Start(); 
     } 
     private void button3_Click(object sender, EventArgs e) 
     { 
      Task t = new Task(() => StartUpdate(this.progressBar3)); 
      t.Start(); 
     } 

     private void StartUpdate(ProgressBar progBar) 
     { 
      for (int i = 1; i <= 100; i++) 
      { 
       UpdateProgressBar(i, progBar); 
       Thread.Sleep(100); 
      } 
     } 

     private void UpdateProgressBar(int i, ProgressBar progBar) 
     { 
      if (progBar.InvokeRequired) //for use with background Task 
      { 
       progBar.Invoke(new Action<int, ProgressBar>(UpdateProgressBar), 
            new Object[] { i, progBar }); 
      } 
      else 
      { 
       //set progress bar: 
       progBar.Value = i; 
       progBar.Refresh(); 

       //set status label: 
       string percentStr = i.ToString() + "%"; 
       PointF location = new PointF(progBar.Width/2 - 10, progBar.Height/2 - 7); 
       using (Graphics gr = progBar.CreateGraphics()) 
       { 
        gr.DrawString(percentStr, new Font("Arial",10), Brushes.Red, location); 
       } 
      } 
     } 

    } 
} 

ответ

0

Это, вероятно, потому, что вы рисуете строку из другого потока. Если вы можете использовать на основе текстового элемента Control вместо этого вы можете использовать BeginInvoke таким же образом, как ProgressBar:

// Label progressLbl 

private void UpdateProgressFromAnotherThread(int completed, int total, string progressText) 
{ 
    this.progBar.BeginInvoke(new Action(() => 
    { 
     this.progBar.Maximum = total; 
     this.progBar.Value = completed; 
    })); 

    this.progressLbl.BeginInvoke(new Action(() => 
    { 
     this.progressLbl.Text = progressText; 
    })); 
} 
+0

Спасибо. Это была моя первая стратегия, но я хотел, чтобы текст лежал поверх вершины ProgressBar, и я все равно не мог найти progresLbl прозрачный фон. – kmote

+0

Итак, возможно, вы могли бы попробовать что-то на основе ответов на этот вопрос (если вы все еще не хотите создавать пользовательский ProgressBar): http://stackoverflow.com/q/10714358/2931053 – Pricey

1

Честно говоря, обычай ProgressBar будет вашим лучшим выбором .. если вы установите его правильно. Я знаю, что не отвечаю на ваш вопрос, поэтому, пожалуйста, не делайте снизу, просто предлагая другое решение. Я еще не тестировал это, но теоретически будет нарисовать процент каждый раз, когда индикатор выполнения должен будет перерисовываться, что произойдет каждый раз, когда значение будет изменено.

Ваша текущая проблема заключается в том, что панель перекрашивается каждый раз, когда вы меняете значение, таким образом, мерцание текста. Если он не перерисовывается, вы увидите процент, который вы рисуете, начинаете накладываться поверх каждого другого, что тоже плохо.

Было бы лучше инкапсулировать все в пределах одного элемента управления с точки зрения дизайна.

class CustomProgressBar : ProgressBar { 
    public CustomProgressBar() : base() {} 

    protected override void OnPaint(PaintEventArgs e) { 
     // Call the OnPaint method of the base class. 
     base.OnPaint(e); 
     string percentStr = this.Value.ToString() + "%"; 
     PointF location = new PointF(this.Width/2 - 10, this.Height/2 - 7); 
     // Call methods of the System.Drawing.Graphics object. 
     e.Graphics.DrawString(percentStr, new Font("Arial",10), Brushes.Red, location); 
    } 
} 
+0

Спасибо, вы могли бы быть правильно. Но для меня просто странно, что мой метод отлично работает с потоком пользовательского интерфейса и только мерцает в фоновом потоке. Но мне нравится ваша упрощенная версия настраиваемого уровня прогресса (гораздо проще, чем версия в принятом ответе, на который я ссылался выше). Мне нужно попробовать – kmote

Смежные вопросы