locked
Button - differences between Click and Tap events ; Click event not raised RRS feed

  • Question

  • Hi,

    I'm getting some issues with buttons, and the event "Click". I compared it with the "Tap" event.

    You'll find below the source code to a sample app (build with WP7.1 ; I didn't tried with WP7.0)

    To see what's wrong, click several times on each button.

    I guess that the buttons "special click" and "special tap" are going in some states, and I need to click outside (or on another button), but I don't understand how to fix it.

    I've a issue in my real app : when the user click on a button, I show a specific Grid and hide the ContentPanel (for fillrate). After that, to hide the specific Grid, we can use the app bar or the back button of the phone. If the user doesn't click in the page (just scrolls for example), and just use the Back Button or the buttons in the app bar, after that the first clicked event on my button isn't raised.

    Thanks,

    MainPage.xaml
    <phone:PhoneApplicationPage   
        x:Class="PhoneApp2.MainPage" 
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
        mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" 
        FontFamily="{StaticResource PhoneFontFamilyNormal}" 
        FontSize="{StaticResource PhoneFontSizeNormal}" 
        Foreground="{StaticResource PhoneForegroundBrush}" 
        SupportedOrientations="Portrait" Orientation="Portrait" 
        shell:SystemTray.IsVisible="True">  
     
        <Grid x:Name="LayoutRoot" Background="Transparent">  
            <Grid.RowDefinitions> 
                <RowDefinition Height="Auto"/>  
                <RowDefinition Height="*"/>  
            </Grid.RowDefinitions> 
            <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">  
                <TextBlock x:Name="ApplicationTitle" Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}"/>  
                <TextBlock x:Name="PageTitle" Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>  
            </StackPanel> 
     
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">  
                <Grid.RowDefinitions> 
                    <RowDefinition Height="Auto"/>  
                    <RowDefinition Height="Auto"/>  
                    <RowDefinition Height="Auto"/>  
                    <RowDefinition Height="Auto"/>  
                </Grid.RowDefinitions> 
                <Grid.ColumnDefinitions > 
                    <ColumnDefinition Width="Auto"/>  
                    <ColumnDefinition Width="Auto"/>  
                    <ColumnDefinition Width="Auto"/>  
                </Grid.ColumnDefinitions> 
     
                <Button Grid.Row="1" x:Name="Button_Normal" Content="normal" Click="Button_Normal_Click" Tap="Button_Normal_Tap"/>  
                <Button Grid.Row="2" x:Name="Button_SpecialClick" Content="special click" Click="Button_SpecialClick_Click" Tap="Button_SpecialClick_Tap"/>  
                <Button Grid.Row="3" x:Name="Button_SpecialTap" Content="special tap" Click="Button_SpecialTap_Click" Tap="Button_SpecialTap_Tap"/>  
     
                <TextBlock Grid.Column="1" Text="click"/>  
                <TextBlock x:Name="TextBlock_Normal_Click" Grid.Column="1" Grid.Row="1" Text="0"/>  
                <TextBlock x:Name="TextBlock_SpecialClick_Click" Grid.Column="1" Grid.Row="2" Text="0"/>  
                <TextBlock x:Name="TextBlock_SpecialTap_Click" Grid.Column="1" Grid.Row="3" Text="0"/>  
     
                <TextBlock Grid.Column="2" Text="tap"/>  
                <TextBlock x:Name="TextBlock_Normal_Tap" Grid.Column="2" Grid.Row="1" Text="0"/>  
                <TextBlock x:Name="TextBlock_SpecialClick_Tap" Grid.Column="2" Grid.Row="2" Text="0"/>  
                <TextBlock x:Name="TextBlock_SpecialTap_Tap" Grid.Column="2" Grid.Row="3" Text="0"/>  
            </Grid> 
        </Grid> 
    </phone:PhoneApplicationPage> 


    and the c# code behind :

    using System;  
    using System.Collections.Generic;  
    using System.Linq;  
    using System.Net;  
    using System.Windows;  
    using System.Windows.Controls;  
    using System.Windows.Documents;  
    using System.Windows.Input;  
    using System.Windows.Media;  
    using System.Windows.Media.Animation;  
    using System.Windows.Shapes;  
    using Microsoft.Phone.Controls;  
    using System.Threading;  
     
    namespace PhoneApp2  
    {  
        public partial class MainPage : PhoneApplicationPage  
        {  
            Int32 normal_Click, normal_Tap, specialClick_Click, specialClick_Tap, specialTap_Click, specialTap_Tap;  
     
            public MainPage()  
            {  
                InitializeComponent();  
            }  
     
            private void Button_Normal_Tap(object sender, GestureEventArgs e)  
            {  
                normal_Tap++;  
                TextBlock_Normal_Tap.Text = normal_Tap.ToString();  
            }  
     
            private void Button_Normal_Click(object sender, RoutedEventArgs e)  
            {  
                normal_Click++;  
                TextBlock_Normal_Click.Text = normal_Click.ToString();  
            }  
     
            private void Button_SpecialClick_Click(object sender, RoutedEventArgs e)  
            {  
                ContentPanel.Visibility = Visibility.Collapsed;  
     
                ThreadPool.QueueUserWorkItem(o => 
                    {  
                        Thread.Sleep(50);  
                        Dispatcher.BeginInvoke(() => 
                        {  
                            ContentPanel.Visibility = Visibility.Visible;  
                            specialClick_Click++;  
                            TextBlock_SpecialClick_Click.Text = specialClick_Click.ToString();  
                        });  
                    });  
            }  
     
            private void Button_SpecialClick_Tap(object sender, GestureEventArgs e)  
            {  
                specialClick_Tap++;  
                TextBlock_SpecialClick_Tap.Text = specialClick_Tap.ToString();  
            }  
     
            private void Button_SpecialTap_Click(object sender, RoutedEventArgs e)  
            {  
                specialTap_Click++;  
                TextBlock_SpecialTap_Click.Text = specialTap_Click.ToString();  
            }  
     
            private void Button_SpecialTap_Tap(object sender, GestureEventArgs e)  
            {  
                ContentPanel.Visibility = Visibility.Collapsed;  
     
                ThreadPool.QueueUserWorkItem(o => 
                    {  
                        Thread.Sleep(50);  
     
                        Dispatcher.BeginInvoke(() => 
                            {  
                                ContentPanel.Visibility = Visibility.Visible;  
                                specialTap_Tap++;  
                                TextBlock_SpecialTap_Tap.Text = specialTap_Tap.ToString();  
                            });  
                    });  
            }  
        }  
    Tuesday, October 11, 2011 7:39 PM

All replies

  • Is the problem you're trying to show the fact that the Click event does not always fire?

    The Click event is dependent upon some legacy code which deals with mouse state.  On the phone, which has no real mouse, the state is simulated.
    The default "ClickMode" for a button in "Release".  This means implies that the control detects a mouse button down followed by a mouse button up.
    When you change the Visibility of the parent control the simlated state get's out of sync.
      You can improve the behavior, somewhat, by using ClickMode="Press" but in my testing this can sometimes cause the opposite problem. 

    This does not affect Tap because the Tap event does not rely on any kind of mouse state.

    You're probably better off using Tap event, unless you have a specific need to use Click.  (ex: for shared code.)

    Tuesday, October 11, 2011 11:15 PM
  • Interesting diversion trying your code. I hadn’t tried any of the new gesture events in 7.1. But did a lot of experimenting writing my own gestures a while back, which I still use.

     

    It appears the new ones are implemented differently than the click events. I never implemented gestures on controls just on transparent panels. Anyways, they all probably start from the touch panels hardware interrupt, and then get implemented in the OS differently.

     

    What I found in the quick testing I did in the emulator was the button looses focus for the click event when you collapse the content panel. Doesn’t seem to affect the gesture events, since they are probably implemented differently.

     

    To make the click events work,

     

    Add;

                        Button_SpecialClick.Focus();

                        Button_SpecialTap.Focus();

     

    In your invokes after you make the content panel visible to get focus back on the buttons. Worked for me in the quick testing I did using the emulator.

     

    One other interesting side affect even after the fix was if you rapidly click any of the buttons the gesture counters lag the event counter. Works fine slowly clicking. Lagging is of no great importance, probably due to the way there were implemented.

     

    Update;

     

    Eric, I could tell there was another reply when it hung for a few seconds. You must have been a few seconds ahead. Your explanation helps understand the differences I could only guess at.

    Tuesday, October 11, 2011 11:16 PM
  • Try using Opacity = 0/1 instead of Visibility = Collapsed/Visible.
    Visibility.Collapsed has some far reaching consequences for what you're doing. It makes the object behave like it's not there and could discard pending events (a collapsed control should not receive any events).

    BTW, be careful about using Tap gestures. When done quickly, they can register as DoubleTap instead of (single) Tap.


    Richard Woo
    Wednesday, October 12, 2011 12:10 AM
  • First of all, thanks for your answers !

    I tried using the Opacity, but the experience is a little smoother when playing with Visibility.

    I prefer not to change the ClickMode of the button, because it's always the same (Release) in every native app.

    Finally, calling the Focus() method on my button gave me the results I wanted.

    Thanks again to all of you !
    Thursday, October 13, 2011 7:21 AM
  • I tried using the Opacity, but the experience is a little smoother when playing with Visibility.
    Also try Opacity with BitmapCache.

    http://msdn.microsoft.com/en-us/library/ff967560(v=vs.92).aspx#BKMK_Hiding

    Choosing Between Visibility and Opacity


    Typically, you will improve your performance by using the P:System.Windows.UIElement.Opacity property with bitmap caching. However, there are times when using the P:System.Windows.UIElement.Visibility property will have better performance, such as when your application contains multiple rich visuals. You should evaluate the performance of each technique on a case-by-case basis.

    Friday, October 14, 2011 8:00 PM