Bawiąc się trochę z Windows Phone natrafiłem na problem, który był dość często zgłaszany w przypadku kontrolki TextBox. Błąd jest śmieszny – w emulatorze zdarzenie jest wywoływane dwukrotnie. Błąd ten w moim projekcie pojawił się w przypadku kontrolki TextBlock i obsługi kliknięcia.

W projekcie potrzebowałem zrobić kontrolkę, która będzie zawierała CheckBox oraz dwa pola tekstowe – TextBlock. Każde kliknięcie na TextBlock miało zmieniać stan kontrolki CheckBox na przeciwny. Niby nic trudnego, ale można sobie wyobrazić moje zdziwienie, kiedy odpaliłem program na emulatorze i nie było żadnej zmiany po kliknięciu. Chwila z debuggerem zaowocowała znalezieniem diagnozy. Zdarzenie jest wywoływane dwukrotnie.

I tu pojawia się pytanie. Czy problem ten występuje na telefonach? Tego niestety nie jestem w stanie sprawdzić, ze względu na brak takowego telefonu. Szperając w sieci też tej informacji nie znalazłem. Z tego powodu postanowiłem przygotować rozwiązanie, które będzie na 100% działało również na telefonach.

W sieci można znaleźć propozycje, w których to autorzy modyfikują skórki kontrolki. Wydaje mi się, że nie jest to najlepsze rozwiązanie ponieważ częściowo zrzekamy się pełnej funkcjonalności produktu. Według mnie lepszym rozwiązaniem jest zapisywanie czasu kliknięć i pomijanie wywołania zdarzenia, jeśli wystąpiło ono zbyt szybko po wcześniejszym. W tym celu potrzebujemy zmiennej lokalnej przechowującej czas ostatniego kliknięcia – w przykładzie nosi ona nazwę clickTime oraz odpowiednio zaprogramowanego zdarzenie. W przykładzie czas pomiędzy kliknięciami został ustalony na 500 milisekund. W przypadku wystąpienia drugiego zdarzenia przed upłynięciem zakładanego czasu jest ono ignorowane.

Całość wygląda następująco:

private DateTime clickTime;

private void tb_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
   TimeSpan timeFromLastClick = DateTime.Now - this.clickTime;
   if (timeFromLastClick.TotalMilliseconds > 500)
   {
      // things to do, e.g. CheckBox status change

      this.clickTime = DateTime.Now;
   }
   else
   {
      e.Handled = true;
   }
}