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. 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:
When the TextBox loses the focus.
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
Laurent Bugnion (GalaSoft)
Subscribe | Twitter | Facebook | Flickr | LinkedIn