This article is also published in my blog.
Introduction
While doing some awesome side project in Windows Phone, I needed a way to have a better control on the Application Bar. I want the ApplicationBar Icon Buttons
and Menu Items to be dynamically added, removed, hide/show, or enable/disable, as well as hooking an event for the specific Icon Button or Menu Items.
Background
What is an ApplicationBar in Windows Phone and how to use it?
In Windows Desktop development, we have a control called Toolbar where you can add a Button, Drop Down Menu, Label, Textbox, or Progressbar and also you can add an Icon to your Buttons or Labels as well.
You can have a button as many as you want, position the control around the Form, and you can also have a toolbar on all sides of your Form.
In Windows Phone, it also has some sort of Toolbar, but it is called "Application Bar".
The Application Bar can have a set of circled white icons that stays at the bottom of the screen if it's in Portrait mode, or at the Right, if you turned your phone in Landscape. The Application Bar can only have two controls and that is, the Icon Button and a Menu Item. Just like what you see below (courtesy from Microsoft)
Unfortunately, it is limited, because you're pretty much stuck of having a maximum of 4 Icon Buttons but lucky enough on the other hand for the Menu Item because you can add as much as you can.
But our main concern is the usability of the Icon Buttons because if you think of a big project, you pretty much has to have different ways of letting your end-users easily navigate around your application and one of them is using an ApplicationBar, but having a maximum of 4 Icon Buttons, is not enough.
So how do we solve the problem? 2 ways, either create a multiple Application Bars or have your Icon Buttons dynamically changing at run-time. Which one do you choose?
Let's take a moment of showing an example of creating a multiple Application Bars. In Windows Phone DevCenter, they wrote a way to do this
How to: Create an Application Bar in Code for Windows Phone
http://msdn.microsoft.com/en-us/library/windowsphone/develop/hh394036(v=vs.92).aspx
As you can see from their example, they have two Application Bars defined in XAML.
Now the problem is, it may soon get very long and unmanageable by means of having a duplicate Menu Items (like what you see there), and what if I have 4 different Application Bars and I need a specific Icon Button to always appear on those Application Bars? So what I have to do is to Copy & Paste the XAML definition of that Icon Button to each Application Bar. Possibly, in overtime, I have to change the icon and text, so I have to go over to each Application Bars and change it again. Manipulating the Icon Buttons on those Application Bars in run-time will again introduce another headache.
So what if we could create an easy way of controlling our Icon Buttons in just one single Application Bar?
I wrote a class called ApplicationBarController to address the problem where we can have a much smoother control over to our Icon Buttons and Menu Items in one Application Bar. What we can do in this class is we can easily Show the Icon Buttons or Menu Items we need for a specific task, as well as Hide them if not needed anymore like. In the animated image above, I demoed how this class works.
Using the code
ApplicationBarController
class
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Microsoft.Phone.Shell;
namespace CAPPLOUD.WP.Controllers
{
public class ApplicationBarController
{
IApplicationBar _appbar;
public ApplicationBarController(IApplicationBar appbar)
{
this._appbar = appbar;
}
Dictionary<string, IApplicationBarIconButton> Buttons { get; set; }
Dictionary<string, IApplicationBarMenuItem> MenuItems { get; set; }
public void AddNewMenuItem(string Text, bool isEnabled, EventHandler e)
{
if (MenuItems == null)
{
MenuItems = new Dictionary<string, IApplicationBarMenuItem>();
}
if (MenuItems.ContainsKey(Text)) { return; }
ApplicationBarMenuItem menuitem = new ApplicationBarMenuItem()
{
Text = Text,
IsEnabled = isEnabled
};
menuitem.Click += e;
MenuItems.Add(Text, menuitem);
}
public void AddNewButton(string Text, string IconUri, bool isEnabled, EventHandler e)
{
if (Buttons == null)
{
Buttons = new Dictionary<string, IApplicationBarIconButton>();
}
if (Buttons.ContainsKey(Text)) { return; }
ApplicationBarIconButton btn = new ApplicationBarIconButton()
{
Text = Text,
IconUri = new Uri(IconUri, UriKind.Relative),
IsEnabled = isEnabled
};
btn.Click += e;
Buttons.Add(Text, btn);
}
public void ShowButtons(params string[] ButtonText)
{
this._appbar.Buttons.Clear();
foreach (string text in ButtonText)
{
if (!_appbar.Buttons.Contains(Buttons[text]))
{
_appbar.Buttons.Add(Buttons[text]);
}
}
}
public void ShowButton(params string[] ButtonText)
{
foreach (string text in ButtonText)
{
if (!_appbar.Buttons.Contains(Buttons[text]))
{
_appbar.Buttons.Add(Buttons[text]);
}
}
}
public void RemoveButtons(params string[] ButtonText)
{
foreach (string text in ButtonText)
{
if (_appbar.Buttons.Contains(Buttons[text]))
{
_appbar.Buttons.Remove(Buttons[text]);
}
}
}
public void RemoveButtons()
{
this._appbar.Buttons.Clear();
}
public void EnableButtons(bool Enabled, params string[] ButtonText)
{
foreach (string text in ButtonText)
{
Buttons[text].IsEnabled = Enabled;
}
}
public void ShowMenuItems(params string[] MenuItemText)
{
this._appbar.MenuItems.Clear();
foreach (string text in MenuItemText)
{
if (!_appbar.MenuItems.Contains(MenuItems[text]))
{
_appbar.MenuItems.Add(MenuItems[text]);
}
}
}
public void ShowMenuItem(params string[] MenuItemText)
{
foreach (string text in MenuItemText)
{
if (!_appbar.MenuItems.Contains(MenuItems[text]))
{
_appbar.MenuItems.Add(MenuItems[text]);
}
}
}
public void RemoveMenuItems(params string[] MenuItemText)
{
foreach (string text in MenuItemText)
{
if (_appbar.MenuItems.Contains(MenuItems[text]))
{
_appbar.MenuItems.Remove(MenuItems[text]);
}
}
}
public void RemoveMenuItems()
{
_appbar.MenuItems.Clear();
}
public void EnableMenuItems(bool Enabled, params string[] MenuItemText)
{
foreach (string text in MenuItemText)
{
MenuItems[text].IsEnabled = Enabled;
}
}
public void ShowAppBar(bool Show)
{
if (this._appbar.IsVisible != Show)
{
this._appbar.IsVisible = Show;
}
}
}
}
This ApplicationBarController class can pretty much do what ever you want. You can:
- Add or Remove an Icon Button or Menu Items
- Show or Hide Icon Buttons or Menu Items
- Enable or Disable an Icon Button or Menu Items.
Here's an easy way you can implement ApplicationBarController class.
First thing you have to do is to hook the ApplicationBar for the current page.
ApplicationBarController appbar = new ApplicationBarController(this.ApplicationBar);
Next is to prepare your Icon Buttons and Menu Items that you are going to need in your project.
void InitializeApplicationBar
{
this.appbar.AddNewButton("add", "/icons/appbar.add.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("save", "/icons/appbar.save.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("cancel", "/icons/appbar.close.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("delete", "/icons/appbar.delete.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("clear", "/icons/appbar.close.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("ff", "/icons/appbar.transport.ff.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("play", "/icons/appbar.transport.play.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("pause", "/icons/appbar.transport.pause.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("rew", "/icons/appbar.transport.rew.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("add menu", "/icons/appbar.add.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewButton("clear menus", "/icons/appbar.close.rest.png",
true, ApplicationBarIconButton_Click);
this.appbar.AddNewMenuItem("Message", true, ApplicationBarMenuItem_Click);
}
private void ApplicationBarIconButton_Click(object sender, EventArgs e)
{
ApplicationBarIconButton btn = (ApplicationBarIconButton)sender;
string text = btn.Text.ToLower();
if (text == "add")
{
MessageBox.Show("Add button was clicked");
}
}
private void ApplicationBarMenuItem_Click(object sender, EventArgs e)
{
ApplicationBarMenuItem menu = (ApplicationBarMenuItem)sender;
string text = menu.Text.ToLower();
}
Then while at run time, you can simple show the Icon Buttons or Menu Items you need for the current task in your page.
this.appbar.ShowButtons(new string[] { "add", "delete", "clear" });
this.appbar.ShowButtons("add", "delete", "clear");
this.appbar.ShowButtons("add", "clear");
and the same way with Menu Items.
One important note is, the Text you give to the Icon Button or Menu Items acts as a case sensitive Key.
Ending
I hope from that class, I am able to help you with your Windows Phone development.
Cheers