Как отучить от залипания DateTimePicker?

Я уверен, многим из Вас приходилось сталкиваться с необходимостью фильтровать данные по временному окну. Для этого на форме размещают пару стандартных DateTimePicker’ов и используют событие ValueChanged для получения данных в выбранном промежутке. Но как только Вы прервете работу обработчика этого события, не дав ему завершиться (сообщением об ошибке или окном отображающем процесс получения данных), Вы столкнетесь, нет, не с ошибкой или глюком, а с особенностью поведения календаря DateTimePicker’а – залипанием.

Для того что бы воспроизвести эту особенность, попробуйте расположить на форме DateTimePicker и написать вот такой обработчик события  ValueChanged:

private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
    MessageBox.Show();
}

Теперь попробуйте изменить период в «календаре»…

Попробовали?
Если же  Вам было лень вопроизводить этот пример, то я раскажу в кратце, что вы могли бы увидеть.
В результате этого эксперимента контрол DateTimePicker переходит в режим «залипания». То есть это вполне запланированное поведение, когда при длительном удержании кнопки с выбором месяца, месяца последовательно изменяются. Но мы же вовсе не этого добивались! И гневное недовольство пользователей нас совсем не обрадует...
Поэтому мы начали разбираться, что к чему.

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

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

Не зря говорят:  “Правильно заданный вопрос - это уже половина ответа”.

Первую проблему можно решить, запустив таймер или просто еще однин поток (мы выбрали простой поток).
Например, вот так:

private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{

    // Создаем поток чтобы дать завершиться обработчику события ValueChanged
    Thread tr = new Thread(ShowMess);
    tr.IsBackground = true;
    tr.Start();
}

void ShowMessThread()
{
    this.Invoke(new runmess(ShowMess));
}

void ShowMess()
{
    MessageBox.Show("test");
}

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

Вторая проблема решается вызовом через Invoke метода обновления из основного потока.

private delegate void runmess();

private void dateTimePicker1_ValueChanged(object sender, EventArgs e)
{
MessageBox.Show("test");

      // Создаем поток чтобы дать завершиться обработчику события ValueChanged
      Thread tr = new Thread(ShowMessThread);
      tr.IsBackground = true;
      tr.Start();
}

void ShowMessThread()
{
      this.Invoke(new runmess(ShowMess));
}

void ShowMess()
{
MessageBox.Show("test");
}

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

 

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags:

Comments

Add comment


 

biuquote
  • Comment
  • Preview
Loading