Vibration Composer is probably the strangest app in this part of the book. A cross between a musical instrument and a handheld massager, this app provides an interesting way to create your own custom vibrating patterns.
Users can do some fun things with this app:
➔ Create a solid vibration to use it like a massager app.
➔ Set the phone on a table while it vibrates and watch it move!
实例下载地址:
Users can do some fun things with this app:
➔ Create a solid vibration to use it like a massager app.
➔ Set the phone on a table while it vibrates and watch it move!
➔ Play music from the Music + Videos hub and then use this app to accompany it with vibrations.
MainPage.xaml:
<phone:PhoneApplicationPage
x:Class="WindowsPhoneApp.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:toolkit="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit"
mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="696"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="PortraitOrLandscape"
shell:SystemTray.IsVisible="True">
<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar>
<shell:ApplicationBarIconButton x:Name="StartStopButton"
Text="start"
IconUri="Shared/Images/appbar.play.png"
Click="StartStopButton_Click"/>
<shell:ApplicationBarIconButton x:Name="DeleteButton"
Text="delelte"
IconUri="Shared/Images/appbar.delete.png"
Click="DeleteButton_Click"/>
<shell:ApplicationBarIconButton x:Name="InstructionButton"
Text="instructions"
IconUri="Shared/Images/appbar.instructions.png"
Click="InstructionButton_Click"/>
<shell:ApplicationBar.MenuItems>
<shell:ApplicationBarMenuItem Text="solid"/>
<shell:ApplicationBarMenuItem Text="alternating fast"/>
<shell:ApplicationBarMenuItem Text="alternation slow"/>
<shell:ApplicationBarMenuItem Text="sos"/>
<shell:ApplicationBarMenuItem Text="phone ring"/>
</shell:ApplicationBar.MenuItems>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>
<ScrollViewer>
<Grid>
<toolkit:WrapPanel x:Name="WrapPanel"/>
<Rectangle x:Name="CurrentPositionRectangle" Visibility="Collapsed"
Width="56" Height="56" Margin="12" Opacity="0.8"
HorizontalAlignment="Left" VerticalAlignment="Top"
Fill="{StaticResource PhoneForegroundBrush}"/>
</Grid>
</ScrollViewer>
</phone:PhoneApplicationPage>
MainPage.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Threading;
using Microsoft.Devices;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
namespace WindowsPhoneApp
{
public partial class MainPage : PhoneApplicationPage
{
// Constructor
public MainPage()
{
InitializeComponent();
this.startStopButton = this.ApplicationBar.Buttons[0]
as IApplicationBarIconButton;
//initialize the timer
this.timer.Interval = TimeSpan.FromSeconds(.1);
this.timer.Tick += Timer_Tick;
foreach (IApplicationBarMenuItem menuItem in this.ApplicationBar.MenuItems)
menuItem.Click += MenuItem_Click;
for (int i = 0; i < buttons.Length; i++)
{
buttons[i] = new Button
{
Content = new Rectangle
{
Margin = new Thickness(0, 7, 0, 5),
Width = 30,
Height = 30
}
};
buttons[i].Click += Button_Click;
this.WrapPanel.Children.Add(buttons[i]);
}
TrimSequence();
PhoneApplicationService.Current.ApplicationIdleDetectionMode = IdleDetectionMode.Disabled;
}
// the squares
Button[] buttons=new Button[90];
//remember the current sequence
Setting<IList<bool>> saveSequence=new Setting<IList<bool>>("Sequence",new List<bool>());
DispatcherTimer timer = new DispatcherTimer();
int sequencePosition;
int sequenceEndPosition = -1;
bool isRunning = false;
IApplicationBarIconButton startStopButton;
protected override void OnNavigatedFrom(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedFrom(e);
this.saveSequence.Value.Clear();
for (int i = 0; i < buttons.Length; i++)
{
this.saveSequence.Value.Add(buttons[i].Tag != null);
}
Stop();
}
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
base.OnNavigatedTo(e);
for (var i = 0; i < this.saveSequence.Value.Count; i++)
{
if (this.saveSequence.Value[i])
TurnOn(this.buttons[i]);
}
TrimSequence();
}
private void Button_Click(object sender, EventArgs e)
{
Button button = sender as Button;
if (button.Tag == null)
TurnOn(button);
else
TurnOff(button);
TrimSequence();
}
private void TurnOn(Button button)
{
button.Tag = true;
(button.Content as Rectangle).Fill =
Application.Current.Resources["PhoneAccentBrush"] as Brush;
}
private void TurnOff(Button button)
{
button.Tag = false;
(button.Content as Rectangle).Fill = null;
}
private void TrimSequence()
{
this.sequenceEndPosition = -1;
for (int i = buttons.Length - 1; i >= 0; i--)
{
this.buttons[i].Opacity = 1;
if (this.sequenceEndPosition == -1)
{
if (this.buttons[i].Tag == null)
this.buttons[i].Opacity = .2;
else
this.sequenceEndPosition = i;
}
}
if (this.isRunning && this.sequenceEndPosition == -1)
{
StartStopButton_Click(this, EventArgs.Empty);
}
}
private void Timer_Tick(object sender,EventArgs e)
{
Point buttonLocation = this.buttons[this.sequencePosition]
.TransformToVisual(this.WrapPanel).Transform(new Point(0, 0));
this.CurrentPositionRectangle.Margin = new Thickness(
buttonLocation.X+12,buttonLocation.Y+12,0,0);
if (this.buttons[this.sequencePosition].Tag != null)
VibrateController.Default.Start(TimeSpan.FromSeconds(.5));
else
VibrateController.Default.Stop();
this.sequencePosition = (this.sequencePosition + 1)
% (this.sequenceEndPosition + 1);
}
private void Stop()
{
this.timer.Stop();
this.startStopButton.IconUri = new Uri("Shared/Images/appbar.play.png", UriKind.Relative);
this.startStopButton.Text = "start";
this.CurrentPositionRectangle.Visibility = Visibility.Collapsed;
this.isRunning = false;
}
private void Clear()
{
foreach (Button button in this.buttons)
TurnOff(button);
}
private void StartStopButton_Click(object sender, EventArgs e)
{
if (this.isRunning)
{
Stop();
return;
}
if (this.sequenceEndPosition == -1)
{
MessageBox.Show("the vibration pattern is empty! You must turn on at least one square on",
"Enpty Sequence", MessageBoxButton.OK);
return;
}
//start
this.startStopButton.IconUri = new Uri("Shared/Images/appbar.stop.png", UriKind.Relative);
this.startStopButton.Text = "stop";
this.CurrentPositionRectangle.Visibility = Visibility.Visible;
this.sequencePosition = 0;
this.isRunning = true;
this.timer.Start();
}
private void MenuItem_Click(object sender, EventArgs e)
{
Clear();
switch ((sender as IApplicationBarMenuItem).Text)
{
case "solid":
TurnOn(this.buttons[0]);
break;
case "alternating fast":
TurnOn(this.buttons[1]);
break;
case "alternating slow":
TurnOn(this.buttons[6]);
TurnOn(this.buttons[7]);
break;
case "sos":
TurnOn(this.buttons[10]);
TurnOn(this.buttons[11]);
TurnOn(this.buttons[14]);
TurnOn(this.buttons[15]);
TurnOn(this.buttons[18]);
TurnOn(this.buttons[19]);
TurnOn(this.buttons[22]);
TurnOn(this.buttons[23]);
TurnOn(this.buttons[24]);
TurnOn(this.buttons[25]);
TurnOn(this.buttons[26]);
TurnOn(this.buttons[27]);
TurnOn(this.buttons[28]);
TurnOn(this.buttons[29]);
TurnOn(this.buttons[30]);
TurnOn(this.buttons[31]);
TurnOn(this.buttons[34]);
TurnOn(this.buttons[35]);
TurnOn(this.buttons[36]);
TurnOn(this.buttons[37]);
TurnOn(this.buttons[38]);
TurnOn(this.buttons[39]);
TurnOn(this.buttons[40]);
TurnOn(this.buttons[41]);
TurnOn(this.buttons[42]);
TurnOn(this.buttons[43]);
TurnOn(this.buttons[46]);
TurnOn(this.buttons[47]);
TurnOn(this.buttons[48]);
TurnOn(this.buttons[49]);
TurnOn(this.buttons[50]);
TurnOn(this.buttons[51]);
TurnOn(this.buttons[52]);
TurnOn(this.buttons[53]);
TurnOn(this.buttons[54]);
TurnOn(this.buttons[55]);
TurnOn(this.buttons[58]);
TurnOn(this.buttons[59]);
TurnOn(this.buttons[62]);
TurnOn(this.buttons[63]);
TurnOn(this.buttons[66]);
TurnOn(this.buttons[67]);
break;
case "phone ring":
TurnOn(this.buttons[17]);
TurnOn(this.buttons[21]);
TurnOn(this.buttons[22]);
TurnOn(this.buttons[23]);
TurnOn(this.buttons[24]);
TurnOn(this.buttons[29]);
TurnOn(this.buttons[33]);
TurnOn(this.buttons[34]);
TurnOn(this.buttons[35]);
TurnOn(this.buttons[36]);
break;
}
}
private void DeleteButton_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Are you sure you want to clear the whole sequence ? ", "Delete Message", MessageBoxButton.OKCancel)
== MessageBoxResult.OK)
{
Clear();
TrimSequence();
}
}
private void InstructionButton_Click(object sender, EventArgs e)
{
}
}
}
Shared/Settings/Setting.cs:
using System.IO.IsolatedStorage;
namespace WindowsPhoneApp
{
// Encapsulates a key/value pair stored in Isolated Storage ApplicationSettings
public class Setting<T>
{
string name;
T value;
T defaultValue;
bool hasValue;
public Setting(string name, T defaultValue)
{
this.name = name;
this.defaultValue = defaultValue;
}
public T Value
{
get
{
// Check for the cached value
if (!this.hasValue)
{
// Try to get the value from Isolated Storage
if (!IsolatedStorageSettings.ApplicationSettings.TryGetValue(
this.name, out this.value))
{
// It hasn't been set yet
this.value = this.defaultValue;
IsolatedStorageSettings.ApplicationSettings[this.name] = this.value;
}
this.hasValue = true;
}
return this.value;
}
set
{
// Save the value to Isolated Storage
IsolatedStorageSettings.ApplicationSettings[this.name] = value;
this.value = value;
this.hasValue = true;
}
}
public T DefaultValue
{
get { return this.defaultValue; }
}
// "Clear" cached value:
public void ForceRefresh()
{
this.hasValue = false;
}
}
}
实例下载地址: