Wp7 vs keyboard vs ApplicationBar vs binding

As you may have read in my previous posts I’m currently trying to iron out some nagging issues with Windows Phone 7 keyboard (SIP). Another problem I’ve hit is when using it in combination with binding and the ApplicationBar. My scenario is straight forward, I have a TextBox for the user’s name which, via binding, changes a view model’s representation of the name (and vice versa). I then have what amounts to a save button in the Application Bar (application bar icon button). When I press the save button I want; a) the keyboard to disappear b) the view model updated with the current text entered for the user name. Sounds simple, and yet it doesn’t work. Making the keyboard disappear is easy enough, I’ve extended the Keyboard helper class to have a HideKeyboard method – which simply does page.Focus(). So what’s the problem? When the save button is pressed it;

  1. calls HideKeyboard which sets the focus to the page
  2. which in turn causes the text box to lose focus and fire the OnPropertyChanged for data binding
  3. calls my SaveName service.

Again seems simple, but the problem is the timing of the events. What actually happens is the execution order is 1->3->2. Why? Well the binding events are only executed once control returns from the function that caused the focus to change. Therefore my service is trying to save the name before the name has been updated, argh! The simplest solution I can think of (please say if you have a better method) is this hack;

void Default_Loaded(object sender, RoutedEventArgs e)
{

    this.keyboardHelper = new KeyboardHelper(this, LayoutRoot);
    this.keyboardHelper.AddKeyUpHander(typeof(TextBox), TabControls_KeyUp);
    this.DataContext = viewModel;
    this.viewModel.PropertyChanged +=
        new PropertyChangedEventHandler(viewModel_PropertyChanged);
}


void saveButton_Click(object sender, EventArgs e)
{
    // hide the keyboard
    this.keyboardHelper.HideKeyboard();
    // [Edit] If you edit one control and then tab to the next this won't work
    // because the 1st control fires the property change but we've not yet pressed saved
    // so I now have to push the values into the view model, i.e. lose some of the clean adv of binding
    this.viewModel.Name = TextBoxName.Text;

    // [Edit 2] Please see comments; 'SS' suggested queing the save via the dispatcher, which is much nicer
    // I'm not sure if you can guarantee the binding will occur first but it's much nicer
    //  Dispatcher.BeginInvoke(() => viewModel.VerifyProfile());
    // remember that we actually want to verify this change
    this.doesWantToVerify = true;
}

private bool doesWantToVerify;
void viewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
    // some view model property has changed but 
    // did we really want to verify as well?
    if (doesWantToVerify)
    {
        doesWantToVerify = false;
        viewModel.VerifyProfile();
    }
}

Advertisements
This entry was posted in keyboard, wp7, wp7dev and tagged , , . Bookmark the permalink.

10 Responses to Wp7 vs keyboard vs ApplicationBar vs binding

  1. SS says:

    Can you use Dispatcher.BeginInvoke(()=> HideKeyboard(); Save())?

    • pauliom says:

      Yes, well sort of, you can’t put the HideKeyboard in there otherwise you end up with the same problem where the binding has yet to fire but you can have the Save in there. The only cavaet I have to that, is I’m not clear if you can rely on the dispatcher firing after the binding hence why I shied away from it. However, it is a *much* nicer solution. If anyone can confirm that the binding/notify is guaranteed to fire before the dispatcher then please let me know because I love to use this mechanism.

    • pauliom says:

      AlexYak, that, together with the mentioned FocusManager sounds really good. I’ll try those and post again. Thanks for the heads-up.

    • pauliom says:

      AlexYak and SS; I’ve experiemented with the two solutions and so far I actually prefer the Dispatcher method. Asking for the binding to refresh is probably a more “pure” solution however, you really need to be able to reference each control whereas the dispatcher mechanism doesn’t require knowledge of the individual controls. Still a work in progress, I’ll try and post the updates.

      • Sam Naseri says:

        I end up with code:

        public static void MakeSureBindingsApplied()
        {
        var focusObj = FocusManager.GetFocusedElement() as TextBox;
        if (focusObj != null)
        {
        var binding = focusObj.GetBindingExpression(TextBox.TextProperty);
        binding.UpdateSource();
        }
        }
        }

        As you can see this method is does not require to specify the control and gets the control instance from FocusManager. but it only supports TextBox which in my application I only used TextBox, and you may add any other control here.

  2. PJ says:

    I don’t know if it will be helpful, but have you considered using Rx for this?

  3. Pingback: 超快递 beta版 » Windows Phone 7 资源汇总(超全)

  4. pauliom says:

    Sam, that’s a nice elegant solution. Thanks for sharing.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s