Проблема с событием DateChanged в MonthCalendar

Пытался гуглить, но ответа толком не нашел.

Наличие формы Windows с элементом управления MonthCalendar и обработкой события DateChanged. проблема связана со сменой месяца щелчком мыши.

Я попытался показать значение счетчика в метке, которое подсчитывается каждый раз, когда вызывается обработчик событий. При изменении месяца обработчик события вызывается 2 раза.

Когда MessageBox.Show("что-нибудь") вызывается при обработке события, обработчик события, кажется, вызывается несколько раз, и календарь начинает изменяться на один месяц назад навсегда.

Кто-нибудь знает, почему?

Следующий код в классе формы окна приводит к описанному поведению:

private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e)
{
    int i = int.Parse(labelDateChanged.Text);
    labelDateChanged.Text = (i + 1).ToString();
    MessageBox.Show(i.ToString());
}

private void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e)
{
    int i = int.Parse(labelDateSelected.Text);
    labelDateSelected.Text = (i + 1).ToString();
}

person Mustafa Temiz    schedule 30.12.2010    source источник


Ответы (3)


Не перехватывать ВСЕ события DateChanged, но решение состоит в том, чтобы обрабатывать события DateChanged, KeyUp и MouseUp.

Событие DateChanged устанавливает логическое значение IsDateChanged в true. Обработка событий KeyUp и MouseUp проверяет наличие IsDateChanged и выполняет необходимый код + устанавливает IsDateChanged в false.

person Mustafa Temiz    schedule 11.01.2011

Никогда не используйте MessageBox в обработчике событий. Элементы управления часто очень путаются, когда фокус смещается в сторону в одном из их событий. Он продолжает прокручиваться так, потому что использует таймер, чтобы обеспечить непрерывную прокрутку, когда вы опираетесь на кнопку «следующий/предыдущий». Каждый тик таймера снова прокручивает календарь. Этот таймер не отключается, пока кнопка мыши не нажимается. Которого он не может видеть, окно сообщения получило сообщение о поднятии мыши, потому что оно перехватило фокус. Это ошибка в собственном элементе управления Windows, но она никогда не проверяется.

Использование Debug.WriteLine() или временного Console.WriteLine() полезно, вывод идет в окно вывода и не мешает событиям управления.

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

Чтобы обойти это поведение, отложите обработку события до тех пор, пока после событие не перестанет выполняться. Элегантно сделано с помощью Control.BeginInvoke(). Нравится:

    private void monthCalendar1_DateChanged(object sender, DateRangeEventArgs e) {
        this.BeginInvoke(new DateRangeEventHandler(delayedChanged), sender, e);
    }
    private void delayedChanged(object sender, DateRangeEventArgs e) {
        // etc..
    }
person Hans Passant    schedule 30.12.2010
comment
У меня есть тяжелый код, который делает много вещей в моем исходном коде. Я мог бы воссоздать проблему, просто вызвав MessageBox.Show(). Как еще я могу сделать много вещей, запускаемых при изменении даты в элементе управления MonthCalendar? - person Mustafa Temiz; 03.01.2011
comment
С другой стороны, не уверен, что это исправит ситуацию, но фокус все равно сбивается. Не уверен, что этот баг был исправлен в Висте, проверить не могу. - person Hans Passant; 03.01.2011
comment
Вы не были уверены, работает ли это в Vista, и теперь я могу точно сказать, что это не так :-( Еще не проверял на Windows 7. - person Mustafa Temiz; 11.01.2011
comment
@HansPassant: я столкнулся с проблемой, окно сообщения получало фокус в обработчике событий, вызывая странное поведение. был решен с помощью вашего обходного пути. Большое спасибо.. - person Iorn Man; 19.03.2013

Не видя вашего кода, трудно точно сказать, в чем проблема, но вполне вероятно, что вы вызываете метод для изменения даты в ответ на щелчок мыши. В документации для события DateChanged говорится:

Событие DateChanged возникает при любом выборе даты с помощью мыши, клавиатуры или кода.

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

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

person Jim Mischel    schedule 30.12.2010
comment
Я добавил код из простой формы, которую я сделал, чтобы изолировать проблему. Дата не изменена. - person Mustafa Temiz; 03.01.2011