Logo
programming4us
programming4us
programming4us
programming4us
Home
programming4us
XP
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server
programming4us
Windows Phone
 
Windows Phone

The App Bar and Controls - Toggling a Stopwatch

- Free product key for windows 10
- Free Product Key for Microsoft office 365
- Malwarebytes Premium 3.7.1 Serial Keys (LifeTime) 2019
3/18/2011 9:35:59 PM
One handy application on a phone is a stopwatch—an ideal use for a ToggleButton as well as the Stopwatch class defined in the System.Diagnostics namespace.

I deliberately spelled the name of the StopWatch project in camel case to avoid confusion with the .NET Stopwatch class. To make the program a little more interesting, I decided that the elapsed time should be displayable in three different formats, corresponding to the members of this enumeration:

Example 1. Silverlight Project: StopWatch File: ElapsedTimeFormat.cs
namespace StopWatch
{
public enum ElapsedTimeFormat
{
HourMinuteSecond,
Seconds,
Milliseconds
}
}

This elapsed time format is an application setting in StopWatch, so it is exposed as a public property in the App class. As usual with application settings, it is saved to isolated storage when the program is deactivated or closed, and retrieved when the program is launched or activated:

Example 2. Silverlight Project: StopWatch File: App.xaml.cs (excerpt)
public partial class App : Application
{
// Application Setting
public ElapsedTimeFormat ElapsedTimeFormat { set; get; }

. . .

private void Application_Launching(object sender, LaunchingEventArgs e)
{
LoadSettings();
}

private void Application_Activated(object sender, ActivatedEventArgs e)
{
LoadSettings();
}

private void Application_Deactivated(object sender, DeactivatedEventArgs e)
{
SaveSettings();
}

private void Application_Closing(object sender, ClosingEventArgs e)
{
SaveSettings();
}

void LoadSettings()
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;

if (settings.Contains("elapsedTimeFormat"))
ElapsedTimeFormat = (ElapsedTimeFormat)settings["elapsedTimeFormat"];
else
ElapsedTimeFormat = ElapsedTimeFormat.HourMinuteSecond;
}

void SaveSettings()
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
settings["elapsedTimeFormat"] = ElapsedTimeFormat;
settings.Save();
}
}

The content area in the XAML file is a bit more extensive than you might expect because it includes a type of “dialog box” that’s used by the user to select the elapsed time format.

So as not to overwhelm you, only the portion of the content area devoted to the operation of the stopwatch is shown here. It consists of just a ToggleButton to turn the stopwatch on and off, and a TextBlock to display the elapsed time.

Example 3. Silverlight Project: StopWatch File: MainPage.xaml (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<!-- Stopwatch display -->
<Grid VerticalAlignment="Center"
Margin="25 0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<TextBlock Name="elapsedText"
Text="0"
Grid.Row="0"
FontFamily="Arial"
FontSize="{StaticResource PhoneFontSizeExtraLarge}"
TextAlignment="Center"
Margin="0 0 0 50"/>

<ToggleButton Name="startStopToggle"
Content="Start"
Grid.Row="1"
Checked="OnToggleButtonChecked"
Unchecked="OnToggleButtonChecked" />
</Grid>

<!-- Rectangle to simulate disabling -->
. . .
<!-- "Dialog Box" to select TimeSpan formatting -->
. . .
</Grid>

The code-behind file defines just three fields; using directives are required for System.Diagnostics and System.Globaliztion.

Example 4. Silverlight Project: StopWatch File: MainPage.xaml.cs (excerpt)
public partial class MainPage : PhoneApplicationPage
{
Stopwatch stopwatch = new Stopwatch();
TimeSpan suspensionAdjustment = new TimeSpan();
string decimalSeparator = NumberFormatInfo.CurrentInfo.NumberDecimalSeparator;
public MainPage()
{
InitializeComponent();
DisplayTime();
}
. . .
void DisplayTime()
{
TimeSpan elapsedTime = stopwatch.Elapsed + suspensionAdjustment;
string str = null;

switch ((Application.Current as App).ElapsedTimeFormat)
{
case ElapsedTimeFormat.HourMinuteSecond:
str = String.Format("{0:D2} {1:D2} {2:D2}{3}{4:D2}",
elapsedTime.Hours, elapsedTime.Minutes,
elapsedTime.Seconds, decimalSeparator,
elapsedTime.Milliseconds / 10);
break;

case ElapsedTimeFormat.Seconds:
str = String.Format("{0:F2} sec", elapsedTime.TotalSeconds);
break;

case ElapsedTimeFormat.Milliseconds:
str = String.Format("{0:F0} msec", elapsedTime.TotalMilliseconds);
break;

}
elapsedText.Text = str;
}
. . .
}

The most important field is an instance of the Stopwatch. Programmers customarily use this class to determine how long a program spends in a particular method. It’s not often used as an actual stopwatch!

You’ll see shortly how the suspensionAdjustment field is used in connection with tombstoning.

The .NET Stopwatch object provides an elapsed time in the form of a TimeSpan object. I couldn’t quite persuade the TimeSpan object to display the elapsed time in precisely the format I wanted, so I ended up doing my own formatting. The decimalSeparator field represents a tiny nod to internationalization.

The DisplayTime method is devoted to setting the Text property of the TextBlock. It accesses the Elapsed property of the Stopwatch and adds the suspensionAdjustment. This is formatted in one of three ways depending on the ElapsedTimeFormat property of the App class.

When pressed, the ToggleButton fires Checked and Unchecked events, which are both handled by the OnToggleButtonChecked method. This method uses the IsChecked property of the ToggleButton to start or stop the Stopwatch object and also to change the text displayed by the button. To keep the display promptly updated, a CompositionTarget.Rendering event simply calls DisplayTime:

Example . Silverlight Project: StopWatch File: MainPage.xaml.cs (excerpt)
void OnToggleButtonChecked(object sender, RoutedEventArgs e)
{
if ((bool)startStopToggle.IsChecked)
{
stopwatch.Start();
startStopToggle.Content = "Stop";
CompositionTarget.Rendering += OnCompositionTargetRendering;
}
else
{
stopwatch.Stop();
startStopToggle.Content = "Start";
CompositionTarget.Rendering -= OnCompositionTargetRendering;
}
}

void OnCompositionTargetRendering(object sender, EventArgs args)
{
DisplayTime();
}

Here it is in action:



As you can see, the program also contains an ApplicationBar. The two buttons are labeled “format” and “reset.” Here’s the definition of the ApplicationBar in the XAML file:

Example 6. Silverlight Project: StopWatch File: MainPage.xaml (excerpt)
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar>
<shell:ApplicationBarIconButton IconUri="/Images/appbar.feature.settings.rest.
png"
Text="format"
Click="OnAppbarFormatClick" />

<shell:ApplicationBarIconButton IconUri="/Images/appbar.refresh.rest.png"
Text="reset"
Click="OnAppbarResetClick" />
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>


The simpler of the two Click methods is the one for resetting the stopwatch. Resetting the .NET Stopwatch object also causes it to stop, so the ToggleButton is explicitly unchecked and suspensionAdjustment is set to zero:

Example 7. Silverlight Project: StopWatch File: MainPage.xaml.cs (excerpt)
void OnAppbarResetClick(object sender, EventArgs args)
{
stopwatch.Reset();
startStopToggle.IsChecked = false;
suspensionAdjustment = new TimeSpan();
DisplayTime();
}

Selecting the elapsed time format is a little more complex. I chose to handle this not with menu items on the ApplicationBar but with something resembling a little dialog box. This dialog box is defined right in the XAML file in the same Grid cell as the main display:

Example 8. Silverlight Project: StopWatch File: MainPage.xaml.cs (excerpt)
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">

<!-- Stopwatch display -->
. . .
<!-- Rectangle to simulate disabling -->
<Rectangle Name="disableRect"
Fill="#80000000"
Visibility="Collapsed" />
<!-- "Dialog Box" to select TimeSpan formatting -->
<Border Name="formatDialog"
Background="{StaticResource PhoneChromeBrush}"
BorderBrush="{StaticResource PhoneForegroundBrush}"
BorderThickness="3"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="Collapsed">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>

<StackPanel Name="radioButtonPanel"
Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="2"
HorizontalAlignment="Center">

<RadioButton Content="Hour/Minute/Seconds"
Tag="HourMinuteSecond" />

<RadioButton Content="Seconds"
Tag="Seconds" />

<RadioButton Content="Milliseconds"
Tag="Milliseconds" />
</StackPanel>

<Button Grid.Row="1" Grid.Column="0"
Content="ok"
Click="OnOkButtonClick" />

<Button Grid.Row="1" Grid.Column="1"
Content="cancel"
Click="OnCancelButtonClick" />
</Grid>
</Border>
</Grid>


Notice that both the Rectangle and the Border have Visibility settings of Collapsed so they are normally absent from the display. The Rectangle covers the entire content area and is used solely to “gray out” the background. The Border is structured much like a traditional dialog box, with three RadioButton controls and two Button controls labeled “ok” and “cancel.”

Notice that the RadioButton controls do not have handlers set for their Checked events, but they do have text strings set to their Tag properties. The Tag property is defined by FrameworkElement and is available to attach arbitrary data on elements and controls. It’s no coincidence that the text strings I’ve set to these TagElapsedTimeFormat enumeration. properties are exactly the members of the

When the user presses the ApplicationBar button labeled “format,” the OnAppbarFormatClick method takes over, making the disableRect and formatDialog elements visible:

Example 9. Silverlight Project: StopWatch File: MainPage.xaml.cs (excerpt)
void OnAppbarFormatClick(object sender, EventArgs args)
{
disableRect.Visibility = Visibility.Visible;
formatDialog.Visibility = Visibility.Visible;

// Initialize radio buttons
ElapsedTimeFormat currentFormat = (Application.Current as App).ElapsedTimeFormat;

foreach (UIElement child in radioButtonPanel.Children)
{
RadioButton radio = child as RadioButton;
ElapsedTimeFormat radioFormat =
(ElapsedTimeFormat)Enum.Parse(typeof(ElapsedTimeFormat),
radio.Tag as string, true);
radio.IsChecked = currentFormat == radioFormat;
}
}

The logic sets the IsChecked property of a particular RadioButton if its Tag property (when converted into an ElapsedTimeFormat enumeration member) equals the ElapsedTimeFormat stored as an application setting. (Easier logic would have been possible if the Tag properties were simply set to 0, 1, and 2 for the integer values of the enumeration members.)

Here’s the displayed dialog box:



No event handlers are attached to the RadioButton controls. After the dialog is display, the next event the program will receive signals whether the user has press the “ok” or “cancel” button:

Example 10. Silverlight Project: StopWatch File: MainPage.xaml.cs (excerpt)
void OnOkButtonClick(object sender, RoutedEventArgs args)
{
foreach (UIElement child in radioButtonPanel.Children)
{
RadioButton radio = child as RadioButton;
if ((bool)radio.IsChecked)
(Application.Current as App).ElapsedTimeFormat =
(ElapsedTimeFormat)Enum.Parse(typeof(ElapsedTimeFormat),
radio.Tag as string, true);
}
OnCancelButtonClick(sender, args);
}

void OnCancelButtonClick(object sender, RoutedEventArgs args)
{
disableRect.Visibility = Visibility.Collapsed;
formatDialog.Visibility = Visibility.Collapsed;
DisplayTime();
}

The routine for the “ok” button checks which RadioButton is now clicked and then sets the application setting with that value. It also calls the “cancel” handler, which “dismisses” the “dialog box” by setting the Visibility properties of disableRect and formatDialog back to Collapsed.

A program such as this presents a bit of a challenge with respect to tombstoning. I decided to ignore issues involving the dialog box. If someone navigates away from the program with the dialog box displayed, it’s no big deal if it’s no longer there when the user returns.

But ideally, you want an active stopwatch to continue running if the user navigates to another application. Of course, it can’t really keep running because in reality the program is terminated.

What the program can do, however, is save the current elapsed time and the clock time as it is being tombstoned. When the program returns, it can use that information to adjust the time shown on the stopwatch. This occurs in the OnNavigatedFrom and OnNavigatedTo methods:

Example 11. Silverlight Project: StopWatch File: MainPage.xaml.cs (excerpt)
protected override void OnNavigatedFrom(NavigationEventArgs args)
{
PhoneApplicationService service = PhoneApplicationService.Current;
service.State["stopWatchRunning"] = (bool)startStopToggle.IsChecked;

service.State["suspensionAdjustment"] = suspensionAdjustment + stopwatch.Elapsed;
service.State["tombstoneBeginTime"] = DateTime.Now;

base.OnNavigatedFrom(args);
}

protected override void OnNavigatedTo(NavigationEventArgs args)
{
PhoneApplicationService service = PhoneApplicationService.Current;

if (service.State.ContainsKey("stopWatchRunning"))
{
suspensionAdjustment = (TimeSpan)service.State["suspensionAdjustment"];

if ((bool)service.State["stopWatchRunning"])
{
suspensionAdjustment += DateTime.Now -
(DateTime)service.State["tombstoneBeginTime"];
startStopToggle.IsChecked = true;
}
else
{
DisplayTime();
}
}
base.OnNavigatedTo(args);
}

Whenever the program starts up again, the .NET Stopwatch object always begins at an elapsed time of zero. That Stopwatch object can’t be adjusted directly. Instead, the suspensionAdjustment field represents the time that elapsed when the program was tombstoned plus the elapsed time of the Stopwatch when tombstoning began. A user could navigate away several times while the stopwatch is running, so this field could be the accumulation of several periods of tombstoning.

For OnNavigatedTo, the simplest case is when the stopwatch is not actively running. All that’s necessary is to set the suspensionAdjustment from the saved value. But if the stopwatch has conceptually been running all this time, then the suspensionAdjustment must be increased by the period of time that elapsed based on the value returned by DateTime.Now.

In actual use, the StopWatch program will appear to be running and keeping track of elapsed time even when it’s not, and it’s that illusion that make the program much more useful than it would be otherwise.

Other -----------------
- The App Bar and Controls - The Button Hierarchy
- The App Bar and Controls - Theme Styles and Precedence
- The App Bar and Controls - The Concept of Content
- The App Bar and Controls - The Basic Button
- The App Bar and Controls - RangeBase and Slider
- The App Bar and Controls - Elements and Controls
- The App Bar and Controls - Jot and the ApplicationBar
- The App Bar and Controls - Jot and Touch
- The App Bar and Controls - Jot and Application Settings
- The App Bar and Controls - ApplicationBar Icons
 
 
Top 10
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 2) - Wireframes,Legends
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Finding containers and lists in Visio (part 1) - Swimlanes
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Formatting and sizing lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Adding shapes to lists
- Microsoft Visio 2013 : Adding Structure to Your Diagrams - Sizing containers
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 3) - The Other Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 2) - The Data Properties of a Control
- Microsoft Access 2010 : Control Properties and Why to Use Them (part 1) - The Format Properties of a Control
- Microsoft Access 2010 : Form Properties and Why Should You Use Them - Working with the Properties Window
- Microsoft Visio 2013 : Using the Organization Chart Wizard with new data
 
programming4us
Windows Vista
programming4us
Windows 7
programming4us
Windows Azure
programming4us
Windows Server