AppBar
is a custom ItemsControl
that wraps a Microsoft.Phone.Shell.ApplicationBar
. As it is an ItemsControl
, it enables you to add buttons and menu items to it, either in code or in XAML, in a manner not unlike the built-in ApplicationBar
.
When the AppBar
control is first loaded, it sets the host page’s ApplicationBar
to its own ApplicationBar
field.
The AppBar.Build
method is used to populate the ApplicationBar
and is called in the following situations:
When its Loaded
event is raised
When its collection of buttons or menu items changes
When a button or menu item’s visibility changes
The Build
method calls the BuildAux
method and prevents cycles from occurring while building is taking place, as shown:
bool building;
void Build()
{
if (building)
{
return;
}
try
{
building = true;
BuildAux();
}
finally
{
building = false;
}
}
After requesting notification of button and menu item visibility changes, discussed in a moment, the Build
method collects the members of its ItemCollection
and, depending on their type, adds them to the ApplicationBar
’s Buttons
or MenuItems
collection (see Listing 8.4).
void BuildAux()
{
applicationBar.Buttons.Clear();
applicationBar.MenuItems.Clear();
foreach (FrameworkElement item in Items.OfType<FrameworkElement>())
{
RegisterForNotification("Visibility", item);
}
var buttonList = (from button in Items.Where(notUIElementOrVisibleFunc)
.OfType<IApplicationBarIconButtonProvider>()
select button.Button).ToList();
if (buttonList.Count > 4)
{
buttonList = buttonList.Take(4).ToList();
}
applicationBar.Buttons.AddRange(buttonList);
var menuItemList = (from item in Items.Where(notUIElementOrVisibleFunc)
.OfType<IApplicationBarMenuItemProvider>()
select item.MenuItem).ToList();
applicationBar.MenuItems.AddRange(menuItemList);
}
Two classes, AppBarIconButtonBase
and AppBarMenuItemBase
, provide an extensibility point that allows you to create your own custom application bar buttons or menu items. If they do not suit your needs, however, you can opt to implement IApplicationBarIconButtonProvider
and IApplicationBarMenuItemProvider
instead.
The task of the custom AppBar
items, such as the AppBarIconButton
and the AppBarMenuItem
, is to wrap an instance of the corresponding built-in ApplicationBarIconButton
or ApplicationBarMenuItem
, and to expose the wrapped item’s properties as dependency properties.
Both IApplicationBarIconButtonProvider
and IApplicationBarMenuItemProvider
have a single property that is used to retrieve the actual ApplicationBarIconButton
or ApplicationBarMenuItem
.
During population of the ApplicationBar
’s Buttons
and MenuItems
properties within the AppBar.BuildAux
method, a Func
named notUIElementOrVisibleFunc
is used to determine the visibility of an item, as shown:
readonly Func<object, bool> notUIElementOrVisibleFunc
= x =>
{
var element = x as UIElement;
return element == null || element.Visibility == Visibility.Visible;
};
No built-in event exists to monitor the Visibility
property of UIElements
. Therefore, to be notified when a button or menu item’s visibility changes, we rely on an attached property and a custom AppBar
method called RegisterForNotification
, which uses a Binding
to listen for button and menu item visibility changes. See the following excerpt:
void RegisterForNotification(
string propertyName,
FrameworkElement element)
{
BindingExpression expression
= element.GetBindingExpression(ItemVisibilityProperty);
if (expression == null)
{
Binding binding = new Binding(propertyName) { Source = element };
element.SetBinding(ItemVisibilityProperty, binding);
}
}
AppBarHyperlinkButton
subclasses AppBarIconButtonBase
to provide support for page navigation and navigation to external resources (see Listing 8.5).
When the base class’s Click
event is raised, the PhoneApplicationFrame
navigates to the NavigateUri
property. If the Uri
is an external resource, the WebBrowserTask
is used instead.
public class AppBarHyperlinkButton : AppBarIconButtonBase
{
public static readonly DependencyProperty NavigateUriProperty
= DependencyProperty.RegisterAttached(
"NavigateUri",
typeof(Uri),
typeof(AppBarHyperlinkButton),
null);
public Uri NavigateUri
{
get
{
return (Uri)GetValue(NavigateUriProperty);
}
set
{
SetValue(NavigateUriProperty, value);
}
}
protected override void OnClick(EventArgs e)
{
base.OnClick(e);
Navigate();
}
void Navigate()
{
Uri uri = NavigateUri;
if (uri == null)
{
return;
}
if (uri.IsAbsoluteUri)
{
WebBrowserTask task = new WebBrowserTask { Uri = uri };
task.Show();
return;
}
var frame = Application.Current.RootVisual as PhoneApplicationFrame;
if (frame == null)
{
return;
}
frame.Navigate(uri);
}
}
Several AppBar
items are in the downloadable sample code, which you are free to use in your own code. If you spend time using the built-in ApplicationBar
I am certain you will appreciate the benefits of wrapping it in a more developer friendly class like the AppBar
.
3.137.212.212