2013-03-14 3 views
2
private void AddMyScrollEventHandlers() 
    { 
     VScrollBar vScrollBar1 = new VScrollBar(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     while (true) 
     { 
      if (vScrollBar1.Value + 1 < vScrollBar1.Maximum) 
      { 
       vScrollBar1.Value = vScrollBar1.Value + 1;  
       label1.Text = vScrollBar1.Value.ToString();      
      }  
      else 
      {   
       break;  
      } 

      System.Threading.Thread.Sleep(200); 
     } 
    } 

    private void button2_Click(object sender, EventArgs e) 
    { 
     // vScrollBar1.Scroll 
    } 

Я новичок в C#. Я работал над свитком. Я хотел бы здесь, если кто-то нажал кнопку1, затем прокрутка автоматически переместится в конец, и я хочу показать постепенное значение в label1. Также, когда кто-то нажимает кнопку button2, прокрутка останавливается.Невозможно нажать кнопку при запуске метода

Теперь проблема label1 не показывает постепенное изменение стоимости. Он показывает значение один раз, когда остановка прокрутки.

Также, когда прокрутка продолжается i, e, когда цикл работает, я не могу нажать кнопку2. На самом деле я не могу нажать на форму.

Кто-то, пожалуйста, дайте мне некоторое представление о том, как это сделать.

ответ

5

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

+0

BackgroundWorker не подходит для этого сценария. Весь процесс связан с UI. Он мог легко использовать таймер оконных форм. –

+0

Вы правы, но я полагаю, что 'System.Threading.Thread.Sleep (200);' представляет задачу, которая будет выполняться в 'DoWork'. В противном случае код не имеет большого смысла –

+0

Ну, это именно то, что ['Timer'] (http://msdn.microsoft.com/en-us/library/system.windows.forms.timer.aspx) предназначен для. –

1

Все события пользовательского интерфейса запускаются в основном потоке приложения, поэтому приложение может обрабатывать только одно событие за раз. Когда приложение обрабатывает событие, никакое другое событие не будет обработано.

Поскольку вы делаете работу, связанные с UI периодически, лучшим вариантом является использование Timer класс:

  1. Капля Timer из панели инструментов в форму.
  2. В окне свойств установите интервал до 200.
  3. Дважды щелкните объект таймера, чтобы создать обработчик события Tick.
  4. Поместите этот код в недавно созданный timer1_Tick метод:

    if (vScrollBar1.Value + 1 < vScrollBar1.Maximum) 
    { 
        vScrollBar1.Value = vScrollBar1.Value + 1;  
        label1.Text = vScrollBar1.Value.ToString();      
    }  
    else 
    {   
        timer1.Stop(); 
    } 
    
  5. Измените ваши методы, как показано ниже:

    private void AddMyScrollEventHandlers() 
    { 
        timer1.Start(); 
    } 
    
    private void button2_Click(object sender, EventArgs e) 
    { 
        timer1.Stop(); 
    } 
    

Теперь вы сделали.

0

Я бы рекомендовал использовать управление BackgroundWorker, как предложено Agustin Meriles. Тем не менее, еще одна важная вещь, которую следует отметить, заключается в том, что вы должны использовать метод Control.Invoke(...) для обновления элементов управления из другого потока.

Я изменил ваш код, протестировал его в примере приложения и, похоже, работает правильно.

Сначала добавьте новый элемент управления BackgroundWorker в форму и назначьте backgroundWorker1_DoWork на его DoWork событие.

Затем, Вы можете использовать код ниже:

private void button1_Click(object sender, EventArgs e) 
{ 
    //code from here is moved to BackgroundWorker control 
    backgroundWorker1.RunWorkerAsync(); 
} 

private void button2_Click(object sender, EventArgs e) 
{ 

} 

private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e) 
{ 
    //while (true) 
    //the condition directly in the while looks more clear to me 
    while (vScrollBar1.Value + 1 < vScrollBar1.Maximum) 
    { 
     //update controls using Invoke method and anonymous functions 
     vScrollBar1.Invoke((MethodInvoker)delegate() { vScrollBar1.Value += 1; }); 

     label1.Invoke((MethodInvoker)delegate() { label1.Text = vScrollBar1.Value.ToString(); }); 

     //when called inside BackgroundWorker, this sleeps the background thread, 
     //so UI should be responsive now 
     System.Threading.Thread.Sleep(200); 
    } 
} 

Если у Вас есть какие-либо проблемы при использовании этого кода, пожалуйста, дайте мне знать.

Update

Как уже упоминалось в комментариях, Вы можете также использовать ProgressChanged событие BackgroundWorker. Это требует дополнительных изменений в коде, но в этом случае более подходит. Вы можете найти информацию об этом здесь: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.progresschanged.aspx.

Если Вы не собираетесь добавить любой другой код с дополнительной обработкой в ​​цикле while, Вы можете также использовать Timer контроль, как это было предложено MD.Unicorn в своем ответе.

+1

Событие 'ProgressChagned' и' ReportProgress' класса 'BackgroundWorker' предназначены для устранения этого. Нет необходимости использовать 'Invoke', используя их. Фактически, использование таймера облегчает все это. –

+0

Да, вы также можете использовать ReportProgress. «Таймер» более подходит в этом конкретном случае, если в цикле 'while' больше не добавляется дополнительная обработка, но если человек, задающий вопрос, хотел бы улучшить код и добавить некоторые другие вычисления и т. Д.,« BackgroundWorker »может быть лучше , –

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