This chapter is taken from book "Programming Windows Phone 7" by Charles Petzold published by Microsoft press. http://www.charlespetzold.com/phone/index.html
The basic program commands like ApplicationBar it is commonly referred to as the app bar might best be implemented in a mechanism developed specifically for the phone and which is intended to provide a consistent user experience for phone users.
ApplicationBar Icons
The ApplicationBar serves the same role as a menu or toolbar that you might find in a conventional Windows program, ApplicationBar and related classes are defined in the Microsoft.Phone.Shell namespace. These classes derive from Object and exist entirely apart from the whole DependencyObject, UIElement, and FrameworkElement class hierarchy of conventional Silverlight programming.
The ApplicationBar is not part of standard Silverlight, so an XML namespace declaration needs to associate the XML "shell" namespace with the .NET namespace Microsoft.Phone.Shell. The standard MainPage.xaml file provides this for you already:
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
ApplicationBar has a property named Buttons which is the content property for the class. The Buttons collection can contain no more than four ApplicationBarIconButton objects. The IconUri and Text fields are required! The text description should be short; it is converted to lower-case for display purposes.
The final MoviePlayer project has an
ApplicationBar defined like this:
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar>
<shell:ApplicationBarIconButton
x:Name="appbarRewindButton"
IconUri="Images/appbar.transport.rew.rest.png"
Text="rewind"
IsEnabled="False"
Click="OnAppbarRewindClick"
/>
<shell:ApplicationBarIconButton
x:Name="appbarPlayButton"
IconUri="Images/appbar.transport.play.rest.png"
Text="play"
IsEnabled="False"
Click="OnAppbarPlayClick"
/>
<shell:ApplicationBarIconButton
x:Name="appbarPauseButton"
IconUri="Images/appbar.transport.pause.rest.png"
Text="pause"
IsEnabled="False"
Click="OnAppbarPauseClick"
/>
<shell:ApplicationBarIconButton
x:Name="appbarEndButton"
IconUri="Images/appbar.transport.ff.rest.png"
Text="to
end"
IsEnabled="False"
Click="OnAppbarEndClick"
/>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
Yes, I have assigned x:Name attributes to all the buttons, but you'll see shortly that I've also reassigned them in code.
The content grid contains the
MediaElement to
play the movie and two TextBlock elements for some status and error messages:
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<MediaElement
Name="mediaElement"
Source="http://www.charlespetzold.com/Media/Walrus.wmv"
AutoPlay="False"
MediaOpened="OnMediaElementMediaOpened"
MediaFailed="OnMediaElementMediaFailed"
CurrentStateChanged="OnMediaElementCurrentStateChanged"
/>
<TextBlock
Name="statusText"
HorizontalAlignment="Left"
VerticalAlignment="Bottom" />
<TextBlock
Name="errorText"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
TextWrapping="Wrap"
/>
</Grid>
The constructor of the MainPage assigns x:Name attributes to the appropriate ApplicationBarIconButton so they can be conveniently referenced in the rest of the classand the four handlers for the ApplicationBar buttons have just one line of code each, and finaly the messy part of a movie-playing program involves the enabling and disabling of the buttons. Because the primary purpose of this program is to demonstrate the use of the ApplicationBar, I've taken a very simple approach here: The Rewind and End buttons are enabled when the media is opened, and the Play and Pause buttons are enabled based on the CurrentState property of the MediaElement:
namespace MoviePlayer
{
public partialclass MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
// Re-assign names already in the XAML file
appbarRewindButton = this.ApplicationBar.Buttons[0]as ApplicationBarIconButton;
appbarPlayButton = this.ApplicationBar.Buttons[1]as ApplicationBarIconButton;
appbarPauseButton = this.ApplicationBar.Buttons[2]as ApplicationBarIconButton;
appbarEndButton = this.ApplicationBar.Buttons[3]as ApplicationBarIconButton;
}
// ApplicationBar buttons
void OnAppbarRewindClick(object sender, EventArgs args)
{
mediaElement.Position = TimeSpan.Zero;
}
void OnAppbarPlayClick(object sender, EventArgs args)
{
mediaElement.Play();
}
void OnAppbarPauseClick(object sender, EventArgs args)
{
mediaElement.Pause();
}
void OnAppbarEndClick(object sender, EventArgs args)
{
mediaElement.Position = mediaElement.NaturalDuration.TimeSpan;
}
// MediaElement events
void OnMediaElementMediaFailed(object sender,ExceptionRoutedEventArgs args)
{
errorText.Text = args.ErrorException.Message;
}
void OnMediaElementMediaOpened(object sender, RoutedEventArgs args)
{
appbarRewindButton.IsEnabled = true;
appbarEndButton.IsEnabled = true;
}
void OnMediaElementCurrentStateChanged(object sender, RoutedEventArgs args)
{
statusText.Text = mediaElement.CurrentState.ToString();
if (mediaElement.CurrentState ==MediaElementState.Stopped ||
mediaElement.CurrentState == MediaElementState.Paused)
{
appbarPlayButton.IsEnabled = true;
appbarPauseButton.IsEnabled = false;
}
else if (mediaElement.CurrentState == MediaElementState.Playing)
{
appbarPlayButton.IsEnabled = false;
appbarPauseButton.IsEnabled = true;
}
}
}
}
Now it looks like this:

Jot and Application Settings
Jot displays finger input using a class named InkPresenter, which originated with tablet interfaces. InkPresenter derives from the Canvas panel, which means you could use the Children property of InkPresenter to design a background image (a yellow legal pad, for example). Or you can ignore the Canvas part of InkPresenter.
The application settings for Jot are encapsulated in a class specifically for that purpose called JotAppSettings. An instance of JotAppSettings is serialized and saved in isolated storage. The class also contains methods to save and load the settings. The project needs a reference to the System.Xml.Serialization library, and JotAppSettings needs several non-standard using directives for System.Collection.Generic, System.IO, System.IO.IsolatedStorage, and System.Xml.Serialization.
Here are the public properties of JotAppSettings that constitute application settings and using the IsolatedStorageSettings class to save these items, but I couldn't get it to work, so I switched to the regular isolated storage facility. Here's the methods:
public List<StrokeCollection> StrokeCollections { get; set; }
publicint PageNumber { set;get; }
publicColor Foreground { set;get; }
publicColor Background { set;get; }
publicint StrokeWidth { set;get; }
public void Save()
{
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
IsolatedStorageFileStream stream = iso.CreateFile("settings.xml");
StreamWriter writer = newStreamWriter(stream);
XmlSerializer ser = newXmlSerializer(typeof(JotAppSettings));
ser.Serialize(writer, this);
writer.Close();
iso.Dispose();
}
The Load method is static because it must create an instance of JotAppSettings by deserializing the file in isolated storage. If that file doesn't exist—which means the program is being run for the first time-then it simply creates a new instance.
public staticJotAppSettings Load()
{
JotAppSettings settings;
IsolatedStorageFile iso = IsolatedStorageFile.GetUserStoreForApplication();
if (iso.FileExists("settings.xml"))
{
IsolatedStorageFileStream stream = iso.OpenFile("settings.xml",FileMode.Open);
StreamReader reader = newStreamReader(stream);
XmlSerializer ser = newXmlSerializer(typeof(JotAppSettings));
settings = ser.Deserialize(reader)asJotAppSettings;
reader.Close();
}
else
{
// Create and initialize new JotAppSettings object
settings = newJotAppSettings();
settings.StrokeCollections = newList<StrokeCollection>();
settings.StrokeCollections.Add(newStrokeCollection());
}
iso.Dispose();
return settings;
}
Jot and Touch
The content area of Jot is tiny but significant:
<Grid
x:Name="ContentPanel"
Grid.Row="1"
Margin="12,0,12,0">
<InkPresenter
Name="inkPresenter"
/>
</Grid>
As the name suggests, the InkPresenter renders virtual ink that comes from stylus or touch input. The InkPresenter doesn't collect that ink on its own. That's your responsibility. (And Silverlight has no built-in handwriting recognition, although there's nothing to prevent you from adding your own.)
The code-behind file requires a
using directive for the
System.Windows.Ink namespace and defines just two
private fields and the OnTouchFrameReported
handler:
public
partial class
MainPage :
PhoneApplicationPage
{
JotAppSettings appSettings = (Application.Current
as App).AppSettings;
Dictionary<int,
Stroke> activeStrokes =
new Dictionary<int,
Stroke>();
public MainPage()
{
InitializeComponent();
inkPresenter.Strokes =
appSettings.StrokeCollections[appSettings.PageNumber];
inkPresenter.Background = new
SolidColorBrush(appSettings.Background);
// Re-assign ApplicationBar button names
appbarLastButton = this.ApplicationBar.Buttons[1]
as
ApplicationBarIconButton;
appbarNextButton = this.ApplicationBar.Buttons[2]
as
ApplicationBarIconButton;
appbarDeleteButton = this.ApplicationBar.Buttons[3]
as
ApplicationBarIconButton;
TitleAndAppbarUpdate();
Touch.FrameReported +=
OnTouchFrameReported;
}
void OnTouchFrameReported(object
sender, TouchFrameEventArgs args)
{
TouchPoint primaryTouchPoint =
args.GetPrimaryTouchPoint(null);
if (primaryTouchPoint !=
null && primaryTouchPoint.Action ==
TouchAction.Down)
args.SuspendMousePromotionUntilTouchUp();
TouchPointCollection touchPoints
= args.GetTouchPoints(inkPresenter);
foreach (TouchPoint
touchPoint in touchPoints)
{
Point pt =
touchPoint.Position;
int id =
touchPoint.TouchDevice.Id;
switch (touchPoint.Action)
{
case
TouchAction.Down:
Stroke stroke = new
Stroke();
stroke.DrawingAttributes.Color = appSettings.Foreground;
stroke.DrawingAttributes.Height =
appSettings.StrokeWidth;
stroke.DrawingAttributes.Width = appSettings.StrokeWidth;
stroke.StylusPoints.Add(new
StylusPoint(pt.X, pt.Y));
inkPresenter.Strokes.Add(stroke);
activeStrokes.Add(id, stroke);
break;
case
TouchAction.Move:
activeStrokes[id].StylusPoints.Add(new
StylusPoint(pt.X, pt.Y));
break;
case
TouchAction.Up:
activeStrokes[id].StylusPoints.Add(new
StylusPoint(pt.X, pt.Y));
activeStrokes.Remove(id);
TitleAndAppbarUpdate();
break;
}
}
}
Jot and the ApplicationBar



Join the conversation! Your thoughts help the community grow.