Guessing if the SIP is visible in a Windows Phone application

For Silverlight applications, Windows Phone does a good job at abstracting the keyboard from the platform. 
As a developer, you drop a TextBox any where in your app and whenever the textbox gets focus:

  • The platform will launch the SIP if the hardware keyboard is not available.  When the SIP comes up,  the platform also applies a TranslateTransform to the RootFrame of the application, so that the SIP takes its space, but the textbox is still visible. 
  • The platform does nothing if the hardware keyboard is available. SIP does not come up, does not get on the way, etc.

Again, all of the above comes for free, and is pretty convenient most of the time.   Unfortunately, every now and then, you do run into a scene that maybe has a button underneath the textbox ( for example, a login window or a  sign-up window with a button near the bottom).   If you are in one of these situations,  the news are not so great. There are no platform events or classes to tell you if a SIP is available and/or when it is shown or hidden.    There is a “hack” that works most of the time:

When SIP is visible, and the screen has been translated,  the transform is applied at the App.RootFrame (which is a PhoneApplicationFrame).   The easiest way to get notified when this Transform changes (to avoid polling) is to data bind to it; using a DependencyProperty, you get free notifications when the property changes (which of course would happen if the SIP is visible. 
Here is a sample snippet, that sets an IsChecked property in a checkbox whenever we think the SIP is visible.

    1: public partial class MainPage : PhoneApplicationPage
    2:    {
    3:        // Constructor
    4:        public MainPage()
    5:        {
    6:            InitializeComponent();
    7:            BeginListenForSIPChanged(); 
    9:        }
   11:        private void BeginListenForSIPChanged()
   12:        {
   13:            PhoneApplicationFrame frame = (App.Current as App).RootFrame;
   14:            Binding b = new Binding("Y");
   15:            b.Source = (frame.RenderTransform as TransformGroup).Children[0] as TranslateTransform;
   16:            SetBinding(RootFrameTransformProperty, b);
   17:        }
   20:        public static readonly DependencyProperty RootFrameTransformProperty = DependencyProperty.Register(
   21:          "RootFrameTransform",
   22:          typeof(double),
   23:          typeof(MainPage),
   24:          new PropertyMetadata(OnRootFrameTransformChanged));
   26:        static void OnRootFrameTransformChanged(DependencyObject source, DependencyPropertyChangedEventArgs e)
   27:        {
   28:            double newvalue = (double) e.NewValue;
   29:            MainPage page = source as MainPage;  
   30:            if ( newvalue < 0.0 )
   31:            {
   32:                page.IsSipVisibleGuess.IsChecked = true; 
   33:            }
   34:            else if ( newvalue == 0.0 )
   35:            {
   36:                page.IsSipVisibleGuess.IsChecked = false ; 
   37:            } 
   39: #if DEBUG 
   40:            else 
   41:                System.Diagnostics.Debug.Assert ( false, "I assumed this would never happen, let me know if it does"); 
   42: #endif 
   44:        }
   46:    }

Full disclaimer, this post begins with guessing. it is not 100% fail-safe.

The scenario where it fails is when you set focus on a textbox and SIP comes up, and then you open the hardware keyboard on the phone. The platform does not always apply the transform immediately.  The snippet is still right, since the transform has not been removed, but it is annoying that hardware keyboard is readily working and transform is still there.

The snippet also does not tell you if the SIP is visible when the TextBox is so high enough on the scene that the rootframe does not get translated at all.

I would recommend you avoid using the trick when you can,  the easiest way to avoid it is not to put buttons that can be covered by the SIP (so no buttons underneath the textbox). . Put the buttons either above the textbox, or on the ApplicationBar. The latter being my preferred approach.

If you want to try it, the source is here.

Happy Windows Phone coding.