none
WPF button in MapItemsControl not reacting to touch events

    Question

  • This is a WPF Bing Maps Control question.

    I use a MapItemsControl to generate a series of graphical symbols on the map. Each symbol is represented by a WPF ToggleButton so that I can interactively click the symbols to select or deselect them. This works fine when I use the mouse.

    But it fails when I click the ToggleButton on a touch screen!

    AFAIK the touch events should be promoted to mouse events if (and only if) the control is not inside a container with the IsManipulationEnabled property set to true. For the Bing Maps Map control, this property is false (at least this is what the Snoop tool says).

    So why are the touch events not promoted to mouse events for buttons hosted inside the Map control?

    Thursday, March 15, 2012 3:40 PM

Answers

  • After a lot of reading, reflecting and snooping I finally found this excellent post by Jaime Rodriguez which describes the phenomenom I am observing:

    Introduction to WPF 4 Multitouch (scroll down to "Mixing and matching approaches")

    The point is that in order to get touch events promoted to mouse events by WPF logic you not only have to set IsManipulationsEnabled="False", but you must also ensure that the TouchDown (and GotTouchCapture) events are not handled.

    The WPF Bing Maps Map control overrides the OnTouchDown method, captures the TouchDevice and sets e.Handled = true. (Sidenote: It unnecessarily does this even when SupportedManipulations="None"). That's why I don't receive promoted mouse events on my button.

    After understanding this, the solution is obvious: I have to implement my own derived button and handle the OnTouchDown and OnTouchUp events/overrides manually and generate the button states (set IsPressed) and events (call OnClick) myself.

    • Marked as answer by candritzky Thursday, March 15, 2012 4:38 PM
    Thursday, March 15, 2012 4:38 PM

All replies

  • After a lot of reading, reflecting and snooping I finally found this excellent post by Jaime Rodriguez which describes the phenomenom I am observing:

    Introduction to WPF 4 Multitouch (scroll down to "Mixing and matching approaches")

    The point is that in order to get touch events promoted to mouse events by WPF logic you not only have to set IsManipulationsEnabled="False", but you must also ensure that the TouchDown (and GotTouchCapture) events are not handled.

    The WPF Bing Maps Map control overrides the OnTouchDown method, captures the TouchDevice and sets e.Handled = true. (Sidenote: It unnecessarily does this even when SupportedManipulations="None"). That's why I don't receive promoted mouse events on my button.

    After understanding this, the solution is obvious: I have to implement my own derived button and handle the OnTouchDown and OnTouchUp events/overrides manually and generate the button states (set IsPressed) and events (call OnClick) myself.

    • Marked as answer by candritzky Thursday, March 15, 2012 4:38 PM
    Thursday, March 15, 2012 4:38 PM
  • Just in case anybody runs into the same problem, here is my code for a touch-enabled button that also works as part of a MapItemsControl.

    Disclaimer: This implementation does not support the different ClickModes since I did not consider them useful with a touch UI.

      public class TouchButton : Button
      {
        protected override void OnTouchDown(TouchEventArgs e)
        {
          if (e.TouchDevice.Capture(this))
          {
            IsPressed = true;
            e.Handled = true;
          }
          base.OnTouchDown(e);
        }
    
        protected override void OnTouchMove(TouchEventArgs e)
        {
          if (e.TouchDevice.Captured == this)
          {
            // Update IsPressed property to indicate if the
            // current touch position is within the element's
            // visuals.
            IsPressed = IsHitTest(e.GetTouchPoint(this).Position);
            e.Handled = true;
          }
          base.OnTouchMove(e);
        }
    
        protected override void OnTouchUp(TouchEventArgs e)
        {
          if (e.TouchDevice.Captured == this)
          {
            ReleaseTouchCapture(e.TouchDevice);
            IsPressed = false;
            
            // Raise Click event if touch up occurs within
            // the element's visuals.
            if (IsHitTest(e.GetTouchPoint(this).Position))
            {
              OnClick();
            }
            
            e.Handled = true;
          }
          base.OnTouchUp(e);
        }
    
        private bool IsHitTest(Point point)
        {
          var hitTestResult = VisualTreeHelper.HitTest(this, point);
          return hitTestResult != null && hitTestResult.VisualHit != null;
        }
    

    Thursday, March 15, 2012 5:25 PM
  • Thanks very much for sharing your answer :)

    twitter: @alastaira blog: http://alastaira.wordpress.com/

    Thursday, March 15, 2012 7:30 PM
    Moderator