Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

When you work with the ApplicationBar in Windows Phone 7, you notice very fast that it is not quite a component like the others. For example, the ApplicationBarIconButton element is not a dependency object, which causes issues because it is not possible to add attached properties to it.

Here are two other issues I stumbled upon, and what workaround I used to make it work anyway.

Code to demonstrate the issues and the workaround can be downloaded here!

Finding a button by name returns null

Since the ApplicationBar is not in the tree of the Silverlight page, finding an element by name fails. For example consider the following code:

<phoneNavigation:PhoneApplicationPage.ApplicationBar>
    <shell:ApplicationBar>
        <shell:ApplicationBar.Buttons>
            <shell:ApplicationBarIconButton
                IconUri="/Resources/edit.png"
                Click="EditButtonClick"
                x:Name="EditButton"/>
            <shell:ApplicationBarIconButton
                IconUri="/Resources/cancel.png"
                Click="CancelButtonClick"
                x:Name="CancelButton"/>
        </shell:ApplicationBar.Buttons>
    </shell:ApplicationBar>
</phoneNavigation:PhoneApplicationPage.ApplicationBar>

with

private void EditButtonClick(
    object sender, 
    EventArgs e)
{
    CancelButton.IsEnabled = false;
    // Fails, CancelButton is always null
}

The CancelButton, even though it is named through an x:Name attribute, and even though it appears in Intellisense in the code behind, is null when it is needed.

To solve the issue, I use the following code:

public enum IconButton
{
    Edit = 0,
    Cancel = 1
}

public ApplicationBarIconButton GetButton(
    IconButton which)
{
    return ApplicationBar.Buttons[(int) which]
        as ApplicationBarIconButton;
}

private void EditButtonClick(
    object sender, 
    EventArgs e)
{
    GetButton(IconButton.Cancel).IsEnabled = false;
}

Updating a Binding when the icon button is clicked

In Silverlight, a Binding on a TextBox’s Text property can only be updated in two circumstances:

  1. When the TextBox loses the focus.
  2. Explicitly by placing a call in code.

In WPF, there is a third option, updating the Binding every time that the Text property changes (i.e. every time that the user types a character). Unfortunately this option is not available in Silverlight). To select option 1, 2 (and in WPF, 3), you use the Mode property of the Binding class.

The issue here is that pressing a button on the ApplicationBar does not remove the focus from the TextBox where the user is currently typing. If the button is a Save button, this is super annoying: The Binding does not get updated on the data object, the object is saved anyway with the old state, and noone understands what just happened.

In order to solve this, you can make sure that the Binding is updated explicitly when the button is pressed, with the following code:

private void SaveButtonClick(object sender, EventArgs e)
{
    // Force update binding first
    var binding
        = MessageTextBox.GetBindingExpression(
            TextBox.TextProperty);

    binding.UpdateSource();

    // Property was updated for sure, now we can save
    var vm = DataContext as MainViewModel;
    vm.Save();
}

Obviously this is less maintainable than the usual way to do things in Silverlight. So be careful when using the ApplicationBar and remember that it is not a Silverlight element like the others!!

Happy coding!

Laurent

 

Print | posted on Tuesday, June 8, 2010 11:06 AM

Feedback

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by timheuer at 6/8/2010 1:02 PM Gravatar
Is the app bar opacity set to something greater than 0?

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Laurent Bugnion at 6/8/2010 8:13 PM Gravatar
Hey Tim,

The Opacity is left untouched. Would that make a difference?

Cheers,
Laurent

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Grumpydev at 6/9/2010 1:35 AM Gravatar
Would it not be "nicer" to update the text box binding using a simple behaviour? Something like this:

using System;
using System.Windows.Controls;
using System.Windows.Interactivity;

namespace SLTextBoxBehaviorTest
{
public class UpdateSourceTriggerPropertyChangedBehavior : Behavior<TextBox>
{
protected override void OnAttached()
{
base.OnAttached();

this.AssociatedObject.TextChanged += TextChanged;
}

protected override void OnDetaching()
{
base.OnDetaching();

this.AssociatedObject.TextChanged -= TextChanged;
}

protected void TextChanged(object sender, TextChangedEventArgs e)
{
var binding = this.AssociatedObject.GetBindingExpression(TextBox.TextProperty);

if (binding == null)
return;

if (binding.ParentBinding.Mode != System.Windows.Data.BindingMode.TwoWay)
return;

binding.UpdateSource();
}
}
}

( http://codepaste.net/7b5pvo )

That should make it behave the same way as setting UpdateSourceTrigger to PropertyChanged in WPF.

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Mark Monster at 6/13/2010 3:57 AM Gravatar
Nice approach to overcome the ApplicationBar button problem. I've also experienced this problem, and used a solution where I create the buttons from codebehind, and keep a reference in there. It's also not perfect, but I think the ApplicationBar will probably need more improvements. I would like to see the ability to put in at least a vectorbased icon (hopefully xaml).

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Matt Casto at 8/7/2010 1:22 PM Gravatar
This is exactly what I was looking for. Thanks for investigating and suggesting work-arounds.

If these controls aren't updated to work like regular buttons by the final release of the tools, I'll be extremely disappointed. I'm really bummed that I can't use EventToCommand on them.

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Laurent at 8/7/2010 3:02 PM Gravatar
We've been talking to the team about it, and unfortunately it is not as easy as it looks, because the App bar is a system-wide component that is getting wrapped in Silverlight. Still, I agree, having a clean control/routed events implementation would be great.

Cheers,
Laurent

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Matt Casto at 8/7/2010 3:09 PM Gravatar
Even if these issues can't be resolved, at the very least some more properties should be available, like Visibility and possibly NavigateUri (or make a ApplicationBarLinkButton).

In any case, without commanding its messaging to the resume! ;-)

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Sam Judson at 8/24/2010 9:42 PM Gravatar
The second issue here is really annoying me. I have 3 textboxes and I don't know how to tell which one has the focus to make sure its databinding is up to date. I don't really want to have to have to manually update all three of them else it kind of defeats the purpose of data binding!

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by Sam Judson at 8/25/2010 2:11 AM Gravatar
Found a solution. You use the FocusManager property to get the control with the current focus.


object focusObj = FocusManager.GetFocusedElement();
if (focusObj != null && focusObj is TextBox)
{
var binding = (focusObj as TextBox).GetBindingExpression(TextBox.TextProperty);
binding.UpdateSource();
}

Sam

# re: Two small issues with Windows Phone 7 ApplicationBar buttons (and workaround)

left by James at 4/12/2011 9:50 AM Gravatar
Q1. Use "sender as" is a alternative way to get instance, ex:
(sender as ApplicationBarIconButton).IsEnabled = false;
Post A Comment
Title:
Name:
Email:
Website:
Comment:
Verification: