C # Winforms: поток, который может управлять пользовательским интерфейсом и может "спать", не останавливая всю программу.Как? - PullRequest
2 голосов
/ 26 августа 2011

OK ...

Похоже, что WinForms и Threading в одной и той же программе - это то, что я не могу легко освоить.

Я пытаюсь сделать пользовательский Numeric Up Downиз двух графических блоков (используются кнопки) и текстовое поле.Да, я могу использовать стандартную форму NumericUpDown, но я хочу сделать другую, выглядящую по-другому.

Я попытался сделать это с таймерами (System.Windows.Forms.Timer).Проблема в том, что когда один таймер встречает «Thread.Sleep (int)», вся программа «засыпает».

Я пытался с потоками.Некоторые типы потоков не могут управлять пользовательским интерфейсом.Затем я попробовал это

private void declare_thread()
{
    //some work
    Thread delay = new Thread(new ThreadStart(delay0));
    delay.Start();
    //some more work
}
//other functions
private void delay0()
{
    //delay_for_500ms.WaitOne();
    this.Invoke((ThreadStart)delegate()
    {
    Thread.Sleep(500);
    if (is_mouse_down)
    timer1.Enabled = true;
    });
}

Результат был таким же, как когда я использовал только таймеры.

Итак, я хочу сделать пользовательский Numeric Up Down.Но я не могу понять это правильно.Я знаю, что делаю это неправильно.Я хочу создать поток, который может управлять пользовательским интерфейсом и не заставляет всю программу останавливаться при вызове Thread.Sleep (int).

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

Ответы [ 4 ]

8 голосов
/ 26 августа 2011

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

Боюсь, вам нужно стиснуть зубы и научиться правильно выполнять нарезку резьбы. Обратите внимание, что сон почти всегда неправильный подход, особенно в потоке пользовательского интерфейса. Вы действительно не сказали, что пытаетесь сделать, но таймер - это хороший способ сказать: «Я хочу выполнить какое-то действие в более поздний момент времени». В .NET есть различных таймеров - какой из них использовать, будет зависеть от того, что вы пытаетесь сделать.

Потоки - это одна из тех тем, которые вы не можете по-настоящему сократить - вам следует прочитать подробное руководство или книгу, в которой подробно об этом рассказывается.

1 голос
/ 26 августа 2011

Чтобы ответить на ваш реальный вопрос, используйте это:

private void declare_thread()
{
    //some work
    Thread delay = new Thread(new ThreadStart(delay0));
    delay.Start();
    //some more work
}

//other functions
private void delay0()
{
    //delay_for_500ms.WaitOne();
    Thread.Sleep(500);
    this.Invoke((ThreadStart)delegate()
    {

    if (is_mouse_down)
    timer1.Enabled = true;
    });
}

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

Если вы хотите подождать полсекунды, прежде чем что-то делать, установите таймер на 500 мс и выйдитефункция.Пусть таймер сообщит вам, когда это будет сделано, чтобы вы могли выполнить вторую половину:

// on the main thread

// la la la doing work
// wait 500ms
var tmr=new Timer{Interval=500};
tmr.Tick+=(s,e)=>{/*action .5sec later*/ btn.Enabled=false; tmr.Enabled=false;};
tmr.Enabled=true;

// and quit
return;
0 голосов
/ 26 августа 2011

Если вы хотите загрузить Async CTP (или подождите C # 5.0), вы можете использовать новые ключевые слова async и await, чтобы создать действительно элегантное решение. 1

public class YourForm : Form
{
  private async void UpPictureBox_Click(object sender, EventArgs args)
  {
    await Task.Delay(500);
    timer1.Enabled = is_mouse_down;
  }

  private async void DownPictureBox_Click(object sender, EventArgs args)
  {
    await Task.Delay(500);
    timer1.Enabled = is_mouse_down;
  }
}

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


1 Обратите внимание, что Async CTP использует TaskEx вместо Task.

0 голосов
/ 26 августа 2011
button.Click += delegate { BeginInvoke(new UiUpdate(delegate { Thread.Sleep(500); // Do Stuff After Sleep };)) };

private delegate void UiUpdate();
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...