Prabhu Kumar

a tech twaddler..

Archive for the ‘Uncategorized’ Category

Windows Phone 7: Building a simple dictionary web client

without comments

Like I mentioned in this post a while back, I came across a dictionary web service called Aonaware that serves up word definitions from various dictionaries and is really easy to use. The services page on their website, http://services.aonaware.com/DictService/DictService.asmx, lists all the operations that are supported by the dictionary service. Here they are,

Word Dictionary Web Service

The following operations are supported. For a formal definition, please review the Service Description.

  • Define
    Define given word, returning definitions from all dictionaries
  • DefineInDict
    Define given word, returning definitions from specified dictionary
  • DictionaryInfo
    Show information about the specified dictionary
  • DictionaryList
    Returns a list of available dictionaries
  • DictionaryListExtended
    Returns a list of advanced dictionaries (e.g. translating dictionaries)
  • Match
    Look for matching words in all dictionaries using the given strategy
  • MatchInDict
    Look for matching words in the specified dictionary using the given strategy
  • ServerInfo
    Show remote server information
  • StrategyList
    Return list of all available strategies on the server

Follow the links above to get more information on each API.

In this post we will be building a simple windows phone 7 client which uses this service to get word definitions for words entered by the user. The application will also allow the user to select a dictionary from all the available ones and look up the word definition in that dictionary. So of all the apis above we will be using only two, DictionaryList() to get a list of all supported dictionaries and DefineInDict() to get the word definition from a particular dictionary.

Before we get started, a note to you all; I would have liked to implement this application using concepts from data binding, item templates, data templates etc. I have a basic understanding of what they are but, being a beginner, I am not very comfortable with those topics yet so I didn’t use them. I thought I’ll get this version out of the way and maybe in the next version I could give those a try.

A somewhat scary mock-up of the what the final application will look like,

AppMockup

Select Dictionary is a list picker control from the silverlight toolkit (you need to download and install the toolkit if you haven’t already). Below it is a textbox where the user can enter words to look up and a button beside it to fetch the word definition when clicked. Finally we have a textblock which occupies the remaining area and displays the word definition from the selected dictionary.

Create a silverlight application for windows phone 7, AonawareDictionaryClient, and add references to the silverlight toolkit and the web service. From the solution explorer right on References and select Microsoft.Phone.Controls.Toolkit from under the .NET tab,

adding-reference-sl-toolkit

Next, add a reference to the web service. Again right click on References and this time select Add Service Reference In the resulting dialog paste the service url in the Address field and press go, (url –> http://services.aonaware.com/DictService/DictService.asmx)

AddingReference

once the service is discovered, provide a name for the NameSpace, in this case I’ve called it AonawareDictionaryService. Press OK. You can now use the classes and functions that are generated in the AonawareDictionaryClient.AonawareDictionaryService namespace.

Let’s get the UI done now. In MainPage.xaml add a namespace declaration to use the toolkit controls,

xmlns:toolkit=”clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone.Controls.Toolkit”

the content of LayoutRoot is changed as follows, (sorry, no syntax highlighting in this post)

<StackPanel x:Name=”TitlePanel” Grid.Row=”0″ Margin=”12,5,0,5″>
<TextBlock x:Name=”ApplicationTitle” Text=”AONAWARE DICTIONARY CLIENT” Style=”{StaticResource PhoneTextNormalStyle}”/>
<!–<TextBlock x:Name=”PageTitle” Text=”page name” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}”/>–>
</StackPanel>

<!–ContentPanel – place additional content here–>
<Grid x:Name=”ContentPanel” Grid.Row=”1″ Margin=”12,0,12,0″>
<Grid.RowDefinitions>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”Auto”/>
<RowDefinition Height=”*”/>
</Grid.RowDefinitions>
<toolkit:ListPicker Grid.Row=”0″ x:Name=”listPickerDictionaryList”
Header=”Select Dictionary :”>
</toolkit:ListPicker>

<Grid Grid.Row=”1″ Margin=”0,5,0,0″>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”*”/>
<ColumnDefinition Width=”Auto” />
</Grid.ColumnDefinitions>

<TextBox x:Name=”txtboxInputWord” Grid.Column=”0″ GotFocus=”OnTextboxInputWordGotFocus” />
<Button x:Name=”btnGo” Grid.Column=”1″ Click=”OnButtonGoClick” >
<Button.Content>
<Image Source=”/images/button-go.png”/>
</Button.Content>
</Button>
</Grid>

<ScrollViewer Grid.Row=”2″ x:Name=”scrollViewer”>
<TextBlock  Margin=”12,5,12,5″  x:Name=”txtBlockWordMeaning” HorizontalAlignment=”Stretch”
VerticalAlignment=”Stretch” TextWrapping=”Wrap”
FontSize=”26″ />
</ScrollViewer>
</Grid>

I have commented out the PageTitle as it occupies too much valuable space, and the ContentPanel is changed to contain three rows. First row contains the list picker control, second row contains the textbox and the button, and the third row contains a textblock within a scroll viewer.

The designer will now be showing the final ui,

designerViewOfUI

Now go to MainPage.xaml.cs, and add the following namespace declarations,

using Microsoft.Phone.Controls;
using AonawareDictionaryClient.AonawareDictionaryService;
using System.IO.IsolatedStorage;

A class called DictServiceSoapClient would have been created for you in the background when you added a reference to the web service. This class functions as a wrapper to the services exported by the web service. All the web service functions that we saw at the start can be access through this class, or more precisely through an object of this class.

Create a data member of type DictServiceSoapClient in the Mainpage class, and a function which initializes it,

DictServiceSoapClient DictSvcClient = null;

private DictServiceSoapClient GetDictServiceSoapClient()
{
if (null == DictSvcClient)
{
DictSvcClient = new DictServiceSoapClient();
}

return DictSvcClient;
}

We have two major tasks remaining. First, when the application loads we need to populate the list picker with all the supported dictionaries and second, when the user enters a word and clicks on the arrow button we need to fetch the word’s meaning.


Populating the List Picker

In the OnNavigatingTo event of the MainPage, we call the DictionaryList() api. This can also be done in the OnLoading event handler of the MainPage; not sure if one has an advantage over the other. Here’s the code for OnNavigatedTo,

protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
DictServiceSoapClient client = GetDictServiceSoapClient();

client.DictionaryListCompleted += new EventHandler<DictionaryListCompletedEventArgs>(OnGetDictionaryListCompleted);

client.DictionaryListAsync();

base.OnNavigatedTo(e);
}

Windows Phone 7 supports only async calls to web services. When we added a reference to the dictionary service, asynchronous versions of all the functions were generated automatically. So in the above function we register a handler to the DictionaryListCompleted event which will occur when the call to DictionaryList() gets a response from the server. Then we call the DictionaryListAsync() function which is the async version of the DictionaryList() api. The result of this api will be sent to the handler OnGetDictionaryListCompleted(),

void OnGetDictionaryListCompleted(object sender, DictionaryListCompletedEventArgs e)
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;
Dictionary[] listOfDictionaries;

if (e.Error == null)
{
listOfDictionaries = e.Result;
PopulateListPicker(listOfDictionaries, settings);
}
else if (settings.Contains(“SavedDictionaryList”))
{
listOfDictionaries = settings[“SavedDictionaryList”] as Dictionary[];
PopulateListPicker(listOfDictionaries, settings);
}
else
{
MessageBoxResult res = MessageBox.Show(“An error occured while retrieving dictionary list, do you want to try again?”, “Error”, MessageBoxButton.OKCancel);

if (MessageBoxResult.OK == res)
{
GetDictServiceSoapClient().DictionaryListAsync();
}
}

settings.Save();
}

I have used IsolatedStorageSettings to store a few things; the entire dictionary list and the dictionary that is selected when the user exits the application, so that the next time when the user starts the application the current dictionary is set to the last selected value. First we check if the api returned any error, if the error object is null e.Result will contain the list (actually array) of Dictionary type objects. If there was an error, we check the isolated storage settings to see if there is a dictionary list stored from a previous instance of the application and if so, we populate the list picker based on this saved list. Note that in this case there are chances that the dictionary list might be out of date if there have been changes on the server. Finally, if none of these cases are true, we display an error message to the user and try to fetch the list again.

PopulateListPicker() is passed the array of Dictionary objects and the settings object as well,

void PopulateListPicker(Dictionary[] listOfDictionaries, IsolatedStorageSettings settings)
{
listPickerDictionaryList.Items.Clear();

foreach (Dictionary dictionary in listOfDictionaries)
{
listPickerDictionaryList.Items.Add(dictionary.Name);
}

settings[“SavedDictionaryList”] = listOfDictionaries;

string savedDictionaryName;
if (settings.Contains(“SavedDictionary”))
{
savedDictionaryName = settings[“SavedDictionary”] as string;
}
else
{
savedDictionaryName = “WordNet (r) 2.0”; //default dictionary, wordnet
}

foreach (string dictName in listPickerDictionaryList.Items)
{
if (dictName == savedDictionaryName)
{
listPickerDictionaryList.SelectedItem = dictName;
break;
}
}

settings[“SavedDictionary”] = listPickerDictionaryList.SelectedItem as string;
}

We first clear all the items from the list picker, add the dictionary names from the array and then create a key in the settings called SavedDictionaryList and store the dictionary list in it. We then check if there is saved dictionary available from a previous instance, if there is, we set it as the selected item in the list picker. And if not, we set “WordNet ® 2.0” as the default dictionary. Before returning, we save the selected dictionary in the “SavedDictionary” key of the isolated storage settings.
Fetching word definitions

Getting this part done is very similar to the above code. We get the input word from the textbox, call into DefineInDictAsync() to fetch the definition and when DefineInDictAsync completes, we get the result and display it in the textblock. Here is the handler for the button click,

private void OnButtonGoClick(object sender, RoutedEventArgs e)
{
txtBlockWordMeaning.Text = “Please wait..”;

IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;

if (txtboxInputWord.Text.Trim().Length <= 0)
{
MessageBox.Show(“Please enter a word in the textbox and press ‘Go'”);
}
else
{
Dictionary[] listOfDictionaries = settings[“SavedDictionaryList”] as Dictionary[];
string selectedDictionary = listPickerDictionaryList.SelectedItem.ToString();

string dictId = “wn”; //default dictionary is wordnet (wn is the dict id)

foreach (Dictionary dict in listOfDictionaries)
{
if (dict.Name == selectedDictionary)
{
dictId = dict.Id;
break;
}
}

DictServiceSoapClient client = GetDictServiceSoapClient();

client.DefineInDictCompleted += new EventHandler<DefineInDictCompletedEventArgs>(OnDefineInDictCompleted);
client.DefineInDictAsync(dictId, txtboxInputWord.Text.Trim());
}
}

We validate the input and then select the dictionary id based on the currently selected dictionary. We need the dictionary id because the api DefineInDict() expects the dictionary identifier and not the dictionary name. We could very well have stored the dictionary id in isolated storage settings too. Again, same as before, we register a event handler for the DefineInDictCompleted event and call the DefineInDictAsync() method passing in the dictionary id and the input word.

void OnDefineInDictCompleted(object sender, DefineInDictCompletedEventArgs e)
{
WordDefinition wd = e.Result;

scrollViewer.ScrollToVerticalOffset(0.0f);

if (wd == null || e.Error != null || wd.Definitions.Length == 0)
{
txtBlockWordMeaning.Text = String.Format(“No definitions were found for ‘{0}’ in ‘{1}'”, txtboxInputWord.Text.Trim(), listPickerDictionaryList.SelectedItem.ToString().Trim());
}
else
{
foreach (Definition def in wd.Definitions)
{
string str = def.WordDefinition;
str = str.Replace(”  “, ” “); //some formatting
txtBlockWordMeaning.Text = str;
}
}
}

When the api completes, e.Result will contain a WordDefnition object. This class is also generated in the background while adding the service reference. We check the word definitions within this class to see if any results were returned, if not, we display a message to the user in the textblock. If a definition was found the text on the textblock is set to display the definition of the word.

Adding final touches, we now need to save the current dictionary when the application exits. A small but useful thing is selecting the entire word in the input textbox when the user selects it. This makes sure that if the user has looked up a definition for a really long word, he doesn’t have to press ‘clear’ too many times to enter the next word,

protected override void OnNavigatingFrom(System.Windows.Navigation.NavigatingCancelEventArgs e)
{
IsolatedStorageSettings settings = IsolatedStorageSettings.ApplicationSettings;

settings[“SavedDictionary”] = listPickerDictionaryList.SelectedItem as string;

settings.Save();

base.OnNavigatingFrom(e);
}

private void OnTextboxInputWordGotFocus(object sender, RoutedEventArgs e)
{
TextBox txtbox = sender as TextBox;

if (txtbox.Text.Trim().Length > 0)
{
txtbox.SelectionStart = 0;
txtbox.SelectionLength = txtbox.Text.Length;
}
}

OnNavigatingFrom() is called whenever you navigate away from the MainPage, since our application contains only one page that would mean that it is exiting (or getting tombstoned).

I leave you with a short video of the application in action, but before that if you have any suggestions on how to make the code better and improve it please do leave a comment.

Until next time…

Written by Prabhu Kumar

December 30th, 2010 at 2:33 pm

Posted in Uncategorized

Windows Phone 7 : Dragging and flicking UI controls

without comments

Who would want to flick and drag UI controls!? There might not be many use cases but I think some concepts here are worthy of a post.

So we will create a simple silverlight application for windows phone 7, containing a canvas element on which we’ll place a button control and an image and then, as the title says, drag and flick the controls. Here’s Mainpage.xaml,

  1. <Grid x:Name=”LayoutRoot” Background=”Transparent”>
  2. <Grid.RowDefinitions>
  3. <RowDefinition Height=”Auto”/>
  4. <RowDefinition Height=”*”/>
  5. </Grid.RowDefinitions>
  6. <!–TitlePanel contains the name of the application and page title–>
  7. <StackPanel x:Name=”TitlePanel” Grid.Row=”0″ Margin=”12,17,0,28″>
  8. <TextBlock x:Name=”ApplicationTitle” Text=”KINETICS” Style=”{StaticResource PhoneTextNormalStyle}”/>
  9. <TextBlock x:Name=”PageTitle” Text=”drag and flick” Margin=”9,-7,0,0″ Style=”{StaticResource PhoneTextTitle1Style}”/>
  10. </StackPanel>
  11. <!–ContentPanel – place additional content here–>
  12. <Grid x:Name=”ContentPanel” Grid.Row=”1″ >
  13. <Canvas x:Name=”MainCanvas” HorizontalAlignment=”Stretch” VerticalAlignment=”Stretch”>
  14. <Canvas.Background>
  15. <LinearGradientBrush StartPoint=”0 0″ EndPoint=”0 1″>
  16. <GradientStop Offset=”0″ Color=”Black”/>
  17. <GradientStop Offset=”1.5″ Color=”BlanchedAlmond”/>
  18. </LinearGradientBrush>
  19. </Canvas.Background>
  20. </Canvas>
  21. </Grid>
  22. </Grid>

the second row in the main grid contains a canvas element, MainCanvas, with its horizontal and vertical alignment set to stretch so that it occupies the entire grid. The canvas background is a linear gradient brush starting with Black and ending with BlanchedAlmond. We’ll add the button and image control to this canvas at run time.

Moving to Mainpage.xaml.cs the Mainpage class contains the following members,

  1. public partial class MainPage : PhoneApplicationPage
  2. {
  3. Button FlickButton;
  4. Image FlickImage;
  5. FrameworkElement ElemToMove = null;
  6. double ElemVelX, ElemVelY;
  7. const double SPEED_FACTOR = 60;
  8. DispatcherTimer timer;

FlickButton and FlickImage are the controls that we’ll add to the canvas. ElemToMove, ElemVelX and ElemVelY will be used by the timer callback to move the ui control. SPEED_FACTOR is used to scale the velocities of ui controls.

Here’s the Mainpage constructor,

  1. // Constructor
  2. public MainPage()
  3. {
  4. InitializeComponent();
  5. AddButtonToCanvas();
  6. AddImageToCanvas();
  7. timer = new DispatcherTimer();
  8. timer.Interval = TimeSpan.FromMilliseconds(35);
  9. timer.Tick += new EventHandler(OnTimerTick);
  10. }

We’ll look at those AddButton and AddImage functions in a moment. The constructor initializes a timer which fires every 35 milliseconds, this timer will be started after the flick gesture completes with some inertia.

Back to AddButton and AddImage functions,

  1. void AddButtonToCanvas()
  2. {
  3. LinearGradientBrush brush;
  4. GradientStop stop1, stop2;
  5. Random rand = new Random(DateTime.Now.Millisecond);
  6. FlickButton = new Button();
  7. FlickButton.Content = “”;
  8. FlickButton.Width = 100;
  9. FlickButton.Height = 100;
  10. brush = new LinearGradientBrush();
  11. brush.StartPoint = new Point(0, 0);
  12. brush.EndPoint = new Point(0, 1);
  13. stop1 = new GradientStop();
  14. stop1.Offset = 0;
  15. stop1.Color = Colors.White;
  16. stop2 = new GradientStop();
  17. stop2.Offset = 1;
  18. stop2.Color = (Application.Current.Resources[“PhoneAccentBrush”] as SolidColorBrush).Color;
  19. brush.GradientStops.Add(stop1);
  20. brush.GradientStops.Add(stop2);
  21. FlickButton.Background = brush;
  22. Canvas.SetTop(FlickButton, rand.Next(0, 400));
  23. Canvas.SetLeft(FlickButton, rand.Next(0, 200));
  24. MainCanvas.Children.Add(FlickButton);
  25. //subscribe to events
  26. FlickButton.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(OnManipulationDelta);
  27. FlickButton.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(OnManipulationCompleted);
  28. }

this function is basically glorifying a simple task. After creating the button and setting its height and width, its background is set to a linear gradient brush. The direction of the gradient is from top towards bottom and notice that the second stop color is the PhoneAccentColor, which changes along with the theme of the device. The line,

stop2.Color = (Application.Current.Resources[“PhoneAccentBrush”] as SolidColorBrush).Color;

does the magic of extracting the PhoneAccentBrush from application’s resources, getting its color and assigning it to the gradient stop.

AddImage function is straight forward in comparison,

  1. void AddImageToCanvas()
  2. {
  3. Random rand = new Random(DateTime.Now.Millisecond);
  4. FlickImage = new Image();
  5. FlickImage.Source = new BitmapImage(new Uri(“/images/Marble.png”, UriKind.Relative));
  6. Canvas.SetTop(FlickImage, rand.Next(0, 400));
  7. Canvas.SetLeft(FlickImage, rand.Next(0, 200));
  8. MainCanvas.Children.Add(FlickImage);
  9. //subscribe to events
  10. FlickImage.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(OnManipulationDelta);
  11. FlickImage.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(OnManipulationCompleted);
  12. }

The ManipulationDelta and ManipulationCompleted handlers are same for both the button and the image.

OnManipulationDelta() should look familiar, a similar implementation was used in the previous post,

  1. void OnManipulationDelta(object sender, ManipulationDeltaEventArgs args)
  2. {
  3. FrameworkElement Elem = sender as FrameworkElement;
  4. double Left = Canvas.GetLeft(Elem);
  5. double Top = Canvas.GetTop(Elem);
  6. Left += args.DeltaManipulation.Translation.X;
  7. Top += args.DeltaManipulation.Translation.Y;
  8. //check for bounds
  9. if (Left < 0)
  10. {
  11. Left = 0;
  12. }
  13. else if (Left > (MainCanvas.ActualWidth – Elem.ActualWidth))
  14. {
  15. Left = MainCanvas.ActualWidth – Elem.ActualWidth;
  16. }
  17. if (Top < 0)
  18. {
  19. Top = 0;
  20. }
  21. else if (Top > (MainCanvas.ActualHeight – Elem.ActualHeight))
  22. {
  23. Top = MainCanvas.ActualHeight – Elem.ActualHeight;
  24. }
  25. Canvas.SetLeft(Elem, Left);
  26. Canvas.SetTop(Elem, Top);
  27. }

all it does is calculate the control’s position, check for bounds and then set the top and left of the control.

OnManipulationCompleted() is more interesting because here we need to check if the gesture completed with any inertia and if it did, start the timer and continue to move the ui control until it comes to a halt slowly,

  1. void OnManipulationCompleted(object sender, ManipulationCompletedEventArgs args)
  2. {
  3. FrameworkElement Elem = sender as FrameworkElement;
  4. if (args.IsInertial)
  5. {
  6. ElemToMove = Elem;
  7. Debug.WriteLine(“Linear VelX:{0:0.00}  VelY:{1:0.00}”, args.FinalVelocities.LinearVelocity.X,
  8. args.FinalVelocities.LinearVelocity.Y);
  9. ElemVelX = args.FinalVelocities.LinearVelocity.X / SPEED_FACTOR;
  10. ElemVelY = args.FinalVelocities.LinearVelocity.Y / SPEED_FACTOR;
  11. timer.Start();
  12. }
  13. }

ManipulationCompletedEventArgs contains a member, IsInertial, which is set to true if the manipulation was completed with some inertia. args.FinalVelocities.LinearVelocity.X and .Y will contain the velocities along the X and Y axis. We need to scale down these values so they can be used to increment the ui control’s position sensibly. A reference to the ui control is stored in ElemToMove and the velocities are stored as well, these will be used in the timer callback to access the ui control. And finally, we start the timer.

The timer callback function is as follows,

  1. void OnTimerTick(object sender, EventArgs e)
  2. {
  3. if (null != ElemToMove)
  4. {
  5. double Left, Top;
  6. Left = Canvas.GetLeft(ElemToMove);
  7. Top = Canvas.GetTop(ElemToMove);
  8. Left += ElemVelX;
  9. Top += ElemVelY;
  10. //check for bounds
  11. if (Left < 0)
  12. {
  13. Left = 0;
  14. ElemVelX *= -1;
  15. }
  16. else if (Left > (MainCanvas.ActualWidth – ElemToMove.ActualWidth))
  17. {
  18. Left = MainCanvas.ActualWidth – ElemToMove.ActualWidth;
  19. ElemVelX *= -1;
  20. }
  21. if (Top < 0)
  22. {
  23. Top = 0;
  24. ElemVelY *= -1;
  25. }
  26. else if (Top > (MainCanvas.ActualHeight – ElemToMove.ActualHeight))
  27. {
  28. Top = MainCanvas.ActualHeight – ElemToMove.ActualHeight;
  29. ElemVelY *= -1;
  30. }
  31. Canvas.SetLeft(ElemToMove, Left);
  32. Canvas.SetTop(ElemToMove, Top);
  33. //reduce x,y velocities gradually
  34. ElemVelX *= 0.9;
  35. ElemVelY *= 0.9;
  36. //when velocities become too low, break
  37. if (Math.Abs(ElemVelX) < 1.0 && Math.Abs(ElemVelY) < 1.0)
  38. {
  39. timer.Stop();
  40. ElemToMove = null;
  41. }
  42. }
  43. }

if ElemToMove is not null, we get the top and left values of the control and increment the values with their X and Y velocities. Check for bounds, and if the control goes out of bounds we reverse its velocity. Towards the end, the velocities are reduced by 10% every time the timer callback is called, and if the velocities reach too low values the timer is stopped and ElemToMove is made null.

Here’s a short video of the program, the video is a little dodgy because my display driver refuses to run the animations smoothly. The flicks aren’t always recognised but the program should run well on an actual device (or a pc with better configuration),

You can download the source code from here: ButtonDragAndFlick.zip

Written by Prabhu Kumar

December 19th, 2010 at 2:35 pm

Posted in Uncategorized

Dictionary Web Service

without comments

Today I came across this web service called aonaware which serves up word definitions from various dictionary databases, so I wrote up a quick windows phone 7 app to check it out and it’s kinda neat.

Here’s a video of the app running on the emulator, I’ll write a post soon.

Written by Prabhu Kumar

November 29th, 2010 at 2:36 pm

Posted in Uncategorized

Windows Phone 7 : UI Control Boundaries

without comments

I was working on an application at work when I needed to figure out a really trivial case, well, trivial in theory at least. All I wanted to know was if a button was completely inside a rectangle. Could anything else be simpler you think. Just check the button bounds against the rectangle bounds,

pseudocode
if (Button.Top > Rectangle.Top &&
      Button.Left > Rectangle.Left &&
      Button.Right < Rectangle.Right &&
      Button.Bottom < Rectangle.Bottom)
{
    //Button is inside rectangle
}

the Right and Bottom of the Button and Rectangle can be calculated using the Width and the Height properties of each. You’d expect this to work correctly, but as far as Windows Phone 7 is concerned there is only one caveat.

I wrote up a simple application to illustrate this. Create a Windows Phone 7 Silverlight application and add the following to the ContentPanel grid in Mainpage.xaml,

  1. <Grid x:Name="ContentPanel" Grid.Row="1">
  2.     <Canvas x:Name="MainCanvas" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
  3.         <TextBlock x:Name="RectangleTop" Canvas.Top="0" />
  4.         <TextBlock x:Name="ButtonTop" Canvas.Top="30" />
  5.         <Rectangle x:Name="ColoredRectangle" Width="480" Height="150" Fill="Coral" Opacity="0.4" Canvas.Top="150" Canvas.Left="0"/>
  6.         <Button x:Name="MyButton" Content="Move Me" Canvas.Top="400" Canvas.Left="160" Background="Purple"/>
  7.     </Canvas>           
  8. </Grid>

the constructor of Mainpage looks like this,

  1. public MainPage()
  2. {
  3.     InitializeComponent();
  4.  
  5.     MyButton.ManipulationDelta += new EventHandler<ManipulationDeltaEventArgs>(OnMyButtonManipulationDelta);
  6.  
  7.     RectangleTop.Text = String.Format("Rectangle Top: {0}", Canvas.GetTop(ColoredRectangle));
  8.     ButtonTop.Text = String.Format("Button Top: {0}", Canvas.GetTop(MyButton));
  9. }

We register for the ManipulationDelta event on the button and update the Text on the two Textblocks to show the Top properties of the rectangle and the button, if you run the program this is how the application will look,

FirstScreen

The OnMyButtonManipulationDelta() function will be called whenever a ManipulationDelta event occurs on the MyButton control, which happens when the user clicks and drags the button around. Here we want to move the button along with the users drag,

  1. void OnMyButtonManipulationDelta(object sender, ManipulationDeltaEventArgs e)
  2. {
  3.     double deltaX = e.DeltaManipulation.Translation.X;
  4.     double deltaY = e.DeltaManipulation.Translation.Y;
  5.  
  6.     double btnX = Canvas.GetLeft(MyButton);
  7.     double btnY = Canvas.GetTop(MyButton);
  8.  
  9.     btnX += deltaX;
  10.     btnY += deltaY;
  11.  
  12.     Canvas.SetLeft(MyButton, btnX);
  13.     Canvas.SetTop(MyButton, btnY);
  14.  
  15.     ButtonTop.Text = String.Format("Button Top: {0}", Canvas.GetTop(MyButton));
  16. }

In this function we get the delta manipulation values along the X and Y axis and add it to the Buttons Left and Top property, this makes sure that the button control moves along with the users finger when he/she clicks and drags the button.

Now when we move the button and place it inside the rectangle the values on the textblocks update,

ButtonInsideRect

Things are fine till here, but they start getting interesting when you move the button to the top of the rectangle,

ButtonTopLessThanRectTop

the Button control appears to be well inside the Rectangle but the Top property of the button is 144 where as that of the Rectangle is 150. The values suggest that the button is outside the rectangle!

This happens because there is more to a button control than what meets the eyes. The button is not confined within the white rectangular boundary but is much bigger than that. When you drag and drop a button control using the visual editor in Visual Studio, the area of the button that is selected is bigger than the button itself, (see image below)

ButtonControlSelected

This is intentional and done to make sure that the target area for the user is a bit larger than the control itself so that the control can be selected easily without requiring too much precision. This, of course, is a nice feature (ask anyone who has tried using a Windows Mobile touch screen device with a finger ;)

Placing the Button control precisely on top of the rectangle like below,

ButtonOnTopOfRect

reveals that there are 12 extra pixels on all sides of the button control. (rectangle top = 150,  button top = 138)

So that is all in this post. In the next post we’ll see how easy it is to pick a button control and flick it, the button will bounce around the screen and come to a halt gradually. Refreshing old memories of marbles ;)

 

Post attachments
Source Code: ButtonBoundaries.zip

Update:
I forgot to add that the same case is also true for textbox and password box control

Update 2
I just recorded a short video of the application in action,

 

Written by Prabhu Kumar

November 22nd, 2010 at 2:46 pm

Posted in Uncategorized

Just another post

without comments

angryBirdsIt’s been a while since my last post so I thought I’ll write a filler. Forgive me but I’m going to start off with some rant. My windows mobile marketplace account hasn’t been accessible for a couple of weeks now. Every time I try logging in I get this annoying error which says,

WE’RE SORRY. AN ERROR HAS OCCURRED.

We encountered an issue connecting your App Hub account with your Xbox Live Profile.
Please visit
Xbox.com and update your contact information.
After you have updated your contact information, please return to the App Hub (
https://users.create.msdn.com/Register) to continue.
View App Hub FAQ
A09/S3D4

The error code at the end keeps changing all the time, heck, I don’t even know if it’s an error code. As suggested, I updated my contact information on xbox.com, made sure that all the information at billing.microsoft.com was alright but still no luck. A little bit of searching on the help forums revealed that many other people were facing the same problem. And I thought Microsoft screwed up big time while migrating the mobile marketplace to the new and “improved” App Hub. What’s worse is that I can’t even see my existing app on the marketplace and I have no idea about the download figures, not that I am making thousands off it but still. And then yesterday I got the Windows Phone Newsletter for October, and it was reassuring in some ways. It said,

On October 11, we told you about App Hub, the single destination for both Windows Phone and Xbox Live indie developers. Although App Hub is now open for all developers to explore, only a small number of developers are currently able to submit Windows Phone 7 apps or games. On November 3, Windows Phone 7 app submission will be open to all registered Windows Phone Marketplace developers.” (emphasis mine)

Early October I had got a mail from Microsoft for early access to the App Hub. But I screwed it up by forgetting to attach the app screenshots (how difficult can mail attachments be!). Anyways, come November 3rd I hope all issues are resolved and access to marketplace is restored so that I can view the existing app and submit the new app I’ve been working on.

Update
Well, November 3rd has come and gone and nothing has changed. Still can’t access the Windows Phone 7 dashboard at AppHub. I have contributed to an existing thread showing my concern, here’s the link,
http://forums.create.msdn.com/forums/p/62093/397994.aspx#397994

Update 2
More forum threads here and here.

 

visualStudio In other news, the windows phone developer tools got an update, this October update includes,

  • A new Bing Maps Control that improves map performance during user gestures.
  • The Capability Detection Tool, which scans your application and reports on detected phone capabilities that will be applied during ingestion to marketplace.
  • The WP Connect Tool, with which you can create a connection between the Windows Phone and your PC without requiring Zune to be running, so you can debug media APIs.

You can download the update from here. Details about the Capability Detection Tool and the WP Connect Tool can be found here and here. I haven’t installed this update as I don’t see the need yet.

 

ProgWinPhone7 And finally, “Programming Windows Phone 7that Charles Petzold has been working on is now available for download and it’s free! You can download the pdf along with the sample code from here.

This is one book which I plan to read from start to end thoroughly. I have read the first two preview versions and highly recommend this to anyone serious about developing for Windows Phone 7. On being asked, Charles said that a print-on-demand soft cover version will be available soon which, of course, I plan to buy.

Written by Prabhu Kumar

October 31st, 2010 at 2:48 pm

Posted in Uncategorized

Windows Phone 7 : Final Release of Developer Tools!

without comments

do-epic-shit-3 The official and the final bits of windows phone 7 developer tools are now available, go download them from here. The installer bundles everything you need to develop for windows phone 7 in a nice little package that includes,

– Visual Studio 2010 Express
– Silverlight for windows phone 7
– XNA Game Studio 4 for windows phone 7
– Expression Blend 4 for Windows Phone 7
– Windows Phone 7 emulator

You also get a phone registration and deployment tool which you can use to register and unlock a wp7 device, if you’re lucky enough to have one that is.The deployment tool works both on a physical device as well as the emulator and can be used to deploy your xap’s directly.

Another interesting bit of news today was the release of Windows Phone 7 Ads SDK, check it out here. I got really excited by this until I installed it and dug a little deeper. The documentation accompanying the install clearly says that, as of now at least, this can only be used by developers in the US,

Capture

disappointing, but hopefully it will be available for others outside of US soon. Off to installing the tools now, ciao.

Update: Forgot to mention about the Windows Phone 7 Training Kit. The samples have been updated to work with the RTM version of the tools and new tutorials have been added for pivot and panorama controls. You can download the kit from here.

Written by Prabhu Kumar

September 16th, 2010 at 2:49 pm

Posted in Uncategorized

Windows Mobile Marketplace: Getting started, App statistics and other details

without comments

tempppppIf you follow me on twitter then this should not be news to you, the Mobile Minesweeper game that I’ve been working on (and off) forever has finally made it to marketplace and is available for download. There were a few surprises for me in store during the entire process. First, the amount of time it took for the app to be approved, one attempt and one working day! And second, the number of downloads! The app has been downloaded over 10,000 times since I made it available on the marketplace 10 days ago, even though the app is free I never expected so many downloads and it came as a pleasant shock. In this post I’ll share some resources that helped me to get started with marketplace and prepare for the entire process. And also some statistics related to my app.

Where do I begin?

To submit apps, you need to register for the marketplace and get a developer account. Go to http://developer.windowsphone.com and click on “Register for the marketplace”. Using this developer account you will also be able to submit apps for Windows Phone 7 when the marketplace opens for submissions early October. Here is a nice walk through the registration process,

Windows Marketplace for Mobile Developer Registration Walk Through

There are a few minor differences between the slides shown above and the present process, but it’s easy to figure out. So far, the marketplace experience for me has been really smooth. Apart from the initial hiccup during registration where my credit card wouldn’t work, app submission and an update have gone through without any problems.

Submitting apps to marketplace

Your application must meet all the application submission requirements and pass several test cases (like 2 hours of hopper test) to be certified. The Windows Mobile 6.5 Application Certification Requirements are available here (pdf) for download, and I suggest going through this document at least once. Here is a walk through the application submission process,

Windows Marketplace for Mobile Application Submission Walk Through

Another great resource is Joel’s article on marketplace, a must read;

http://www.codeproject.com/KB/windows/WiMoMarketPlc.aspx

App Statistics

From the start, I designed the app to support 3 resolutions 240×320, 240×400 and 480×800. I think that these are probably the most popular resolutions for windows mobile devices. The only other hardware requirement is that the device should have a touch screen. I had submitted the app for the US catalogue first, and after it passed certification I submitted the same for other English markets which include Australia, Canada, UK, India, and Singapore. Here are a few numbers,

EN-US Catalogue – available for 10 days

EN-US

 

AU, CA, UK, IN and SG Catalogue –available for 8 days

EN-AU

EN-CA

EN-GB

EN-IN

EN-SG

Clearly, US is by far the biggest market, no surprise really. If you happen to try out the app, do let me know what you think. Any suggestions or feedbacks are welcome. Goodbye. Until next time.

Written by Prabhu Kumar

September 5th, 2010 at 2:50 pm

Posted in Uncategorized

Edit boxes and default text selection

without comments

While working on an application of mine, I had to display ‘Help’ information. I chose to use a read-only multiline edit box along with SetWindowText() to display the text, sounds simple enough. But I ran into a small but annoying problem. The text displayed was all selected, and I thought why would the text be selected by default!?

Here is a sample program to demonstrate this,

  1. #include <windows.h>
  2. #include <aygshell.h>
  3. #include "resource.h"
  4.  
  5. HINSTANCE g_hInst;
  6.  
  7. BOOL CALLBACK EditBoxSelTextDlgProc(HWND, UINT, WPARAM, LPARAM);
  8. void AlignComponents(HWND hDlg);
  9. void InitializeComponents(HWND hDlg);
  10.  
  11. int WinMain(HINSTANCE hInst, HINSTANCE hPrevInst,
  12.             LPTSTR lpCmdLine, int nCmdShow)
  13. {
  14.     g_hInst = hInst;
  15.  
  16.     DialogBox(hInst, MAKEINTRESOURCE(IDD_PPC_EDITBOXTEXTSEL), NULL, EditBoxSelTextDlgProc);
  17.     return 0;
  18. }
  19.  
  20. BOOL CALLBACK EditBoxSelTextDlgProc(HWND hDlg, UINT uMessage, WPARAM wParam, LPARAM lParam)
  21. {
  22.     int wmID, wmEvent;
  23.     PAINTSTRUCT ps;
  24.     HDC hdc;
  25.  
  26.     switch(uMessage)
  27.     {
  28.         case WM_INITDIALOG:
  29.             {
  30.                 SHINITDLGINFO shidi;
  31.                 SHMENUBARINFO mbi;
  32.  
  33.                 memset(&shidi, 0, sizeof(shidi));
  34.                 memset(&mbi, 0, sizeof(mbi));
  35.  
  36.                 shidi.dwMask = SHIDIM_FLAGS;
  37.                 shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU;
  38.                 shidi.hDlg = hDlg;
  39.                 SHInitDialog(&shidi);
  40.  
  41.                 mbi.cbSize = sizeof(mbi);
  42.                 mbi.hwndParent = hDlg;
  43.                 mbi.nToolBarId = IDR_MENU_EDITBOXTEXTSEL;
  44.                 mbi.hInstRes = g_hInst;
  45.  
  46.                 if(!SHCreateMenuBar(&mbi))
  47.                 {
  48.                     printf("Error creating menu bar, errcode:0x%x\n", GetLastError());
  49.                 }
  50.  
  51.                 AlignComponents(hDlg);
  52.  
  53.                 InitializeComponents(hDlg);
  54.             }
  55.             return TRUE;
  56.  
  57.         case WM_COMMAND:
  58.             {
  59.                 wmID = LOWORD(wParam);
  60.                 wmEvent = HIWORD(wParam);
  61.  
  62.                 switch(wmID)
  63.                 {
  64.                     case IDM_EXIT:
  65.                         EndDialog(hDlg, uMessage);
  66.                         break;
  67.                 }
  68.             }
  69.             break;
  70.  
  71.         case WM_PAINT:
  72.             {
  73.                 hdc = BeginPaint(hDlg, &ps);
  74.  
  75.                 EndPaint(hDlg, &ps);
  76.             }
  77.             break;
  78.     }
  79.     return FALSE;
  80. }
  81.  
  82. void AlignComponents(HWND hDlg)
  83. {
  84.     HWND hTemp = NULL;
  85.     RECT rect = {0, 0, 0, 0};
  86.     int x=0, y=0, width=0, height=0;
  87.     const int insetX = 3;
  88.     const int insetY = 3;
  89.  
  90.     GetClientRect(hDlg, &rect);
  91.  
  92.     hTemp = GetDlgItem(hDlg, IDC_EDITBOX);
  93.     if (hTemp)
  94.     {
  95.         x = rect.left + insetX;
  96.         y = rect.top + insetY;
  97.         width = (rect.right – rect.left – 2*insetX);
  98.         height = (rect.bottom – rect.top – 2*insetY);
  99.  
  100.         MoveWindow(hTemp, x, y, width, height, FALSE);
  101.     }
  102. }
  103.  
  104. const TCHAR message[] = TEXT("Lorem ipsum dolor sit amet, consectetur adipisicing elit, \
  105. sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. \
  106. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris \
  107. nisi ut aliquip ex ea commodo consequat.\
  108. \r\n\r\n\
  109. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum \
  110. dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non \
  111. proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\
  112. ");
  113.  
  114. void InitializeComponents(HWND hDlg)
  115. {
  116.     HWND hTemp = GetDlgItem(hDlg, IDC_EDITBOX);
  117.  
  118.     if (hTemp)
  119.     {
  120.         SetWindowText(hTemp, message);
  121.     }
  122. }

 

This is usual stuff. Display a dialog box from WinMain(), initialize the dialog and the menubar in dialog proc under the WM_INITDIALOG message. The functions of interest would be AlignComponents() and InitializeComponents(). The dialog contains a single multiline edit box, AlignComponents() resizes the edit box so it occupies the entire screen, and InitializeComponents() calls SetWindowText() to set the text on the edit box control.

If you run this program, here is how it’ll look,

image

So you see the problem there. Skimming through the edit box messages, I came across EM_SETSEL message. This message selects a range of characters in an edit control, and if you pass –1 to it, any current selection is removed. So after the SetWindowText() call in InitializeComponents(), I put this line,

SendMessage(hTemp, EM_SETSEL, (WPARAM)-1, (LPARAM)0);

but if it was this simple I wouldn’t be writing this post, would I? In short, it didn’t work.

I thought maybe I am sending the EM_SETSEL message too early, even before the edit control is ready to process it perhaps? So the next step was to find the right place from where the message could be sent. So, one by one, I went through all the messages sent to dialog proc until the dialog is shown and found WM_ACTIVATE could be the right place. And it indeed was.

Adding the following switch case to dialog proc did the trick,

  1. case WM_ACTIVATE:
  2.     SendMessage(GetDlgItem(hDlg, IDC_EDITBOX), EM_SETSEL,
  3.         (WPARAM)-1, (LPARAM)0);
  4.     break;

 

The edit control now shows up without any selected text.

image

Written by Prabhu Kumar

August 20th, 2010 at 2:51 pm

Posted in Uncategorized

HTC HD2, Accelerometer and Windows Phone 7 – Source Code

with 2 comments

If you haven’t seen the video demo in my last post, I suggest you watch it first to get a better understanding. So in this post we are going to see how the WCF service, the .NET Compact Framework application running on HD2 and the Silverlight application running on the Windows Phone 7 emulator work together.


The Objective

We are going to write three applications, a simple WCF service hosted in a windows console application which implements two functions, one called UploadAccelData() and the other DownloadAccelData(). A .NET Compact Framework application for HD2 which calls the WCF services’ UploadAccelData() function periodically and passes it the x, y and z components of the acceleration vector. A silverlight application for Windows Phone 7 which calls into DownloadAccelData() periodically and gets the accelerometer data off it.

For those of you who want to jump straight into the code, you can download it from the following links,

Download ConsoleApp.zip – VS 2008 solution which contains two projects. One, the console application which hosts the WCF service and two the Compact Framework application which runs on HD2

Download WCFClient_WP7Emu.zip – Windows Phone 7 application which runs on the emulator

Creating the WCF service
I will be using Visual Studio 2008 for creating the service and the .net cf application. Open VS 2008 in administrator mode and create a windows console application in Visual C#. It is important that you start visual studio in administrator mode otherwise you might get an error while deploying the service depending on your access rights on the machine. Now lets add a WCF service which will be hosted by this console application. Right click on the project and select “Add –> New Item..”. In the next dialog select “WCF Service” and give a name to it. I call it “AccelerometerService”.

Creating accelerometer service

With this three files will be added to your project AccelerometerService.cs, IAccelerometerService.cs and App.Config. Open App.Config and change a few things in it, first change binding="wsHttpBinding" to binding="basicHttpBinding" since .net compact framework only supports basicHttpBinding. Next change the BaseAddress from,

<add baseAddress="http://localhost:8731/Design_Time_Addresses/ConsoleApp/AccelerometerService/" /> to

<add baseAddress="http://192.168.2.2:8731/ConsoleApp/AccelerometerService/" />

Again, it is important that you change “localhost” to the ip address of your machine. This is because we will be using this address from the compact framework application to refer to the service, so we need the address of the machine where the service is running. Using “localhost” from the compact framework application would mean a totally different thing. Here I use 192.168.2.2 which is the IP address assigned to my machine by the wireless router that I am using. Be sure to change this IP address depending on your machine setup.

Open Program.cs and add the following code in the Main() function,

static void Main(string[] args)
{
    ServiceHost accelService = new ServiceHost(typeof(AccelerometerService));

    try
    {
        accelService.Open();
        Console.WriteLine("Accel service is running at:{0}", accelService.BaseAddresses[0].AbsoluteUri);
        Console.WriteLine("Press <ENTER> to terminate the service..");

        Console.ReadLine();
    }
    catch (Exception ex)
    {
        Console.WriteLine("An exception occured while creating the serivce. {0}", ex.Message);
        accelService.Abort();
    }
}

Here we are creating an instance of our AccelerometerService and calling Open() on it to start the service. The address where the service is running is output to the console and the service waits for any key to be pressed after which it will be terminated. Now build and run your project, you should see this console window,

Console service running

Now to check our service, open internet explorer and browse to the base address that we entered above,

http://192.168.2.2:8731/ConsoleApp/AccelerometerService/

and you should see this,

sanity check for service IE

If your browser is showing the same thing then great! We are progressing well.

Now lets implement our upload and download functions. Open IAccelerometerService.cs and add the following declarations to the interface,

[OperationContract]
void UploadAccelData(int x, int y, int z);

[OperationContract]
void DownloadAccelData(out int x, out int y, out int z);

To keep things simple I am passing only the x, y and z components of the vector, other information from the accelerometer like Roll and Pitch are ignored for simplicity, though adding those shouldn’t be rocket science. We will be implementing these functions in our AccelerometerService class. Open AccelerometerService.cs and add the following member variables to the AccelerometerService class,

static int _accelX;
static int _accelY;
static int _accelZ;

and add the following function definitions to the same class,

public void UploadAccelData(int x, int y, int z)
{
        _accelX = x;
        _accelY = y;
        _accelZ = z;

        Console.WriteLine("UploadAccelData: X:{0}, Y:{1}, Z:{2}", x, y, z);

}

public void DownloadAccelData(out int x, out int y, out int z)
{
        x = _accelX;
        y = _accelY;
        z = _accelZ;
}

This completes our console app and the WCF service that it will be hosting.

Creating the Compact Framework Application for HD2
Now lets go ahead and add a smart device compact framework C# application to the same solution in VS 2008. Right click on the solution and select “Add –> New Project..”. In the Add New Project dialog select Smart Device under Visual C# and add a new project, WCFClient_HD2.

HD2 CF add new project

in the next screen select “Windows Mobile 6 Professional SDK” as the target platform and “.NET CF Version 3.5”, choose Device Application and press OK.

HD2 cf project type

I have designed the form to show the x, y and z values from the accelerometer and a button to start and stop the sensor. Also, add a timer which fires every 100ms and is initially disabled.

cf form and timer

Now to this project, we will add a reference to the WCF service. First make sure that the service is running, deploy the ConsoleApp project. Right click on WCFClient_HD2 and select “Add Web Reference..”. In the next dialog, enter the URL of the service and press Go.

 adding reference to service

If everything goes well, our AccelerometerService should be found and you will be presented with this dialog,

give a name to the web reference, in this case “AccelerometerService” and select “Add Reference” button. Now the functionalities offered by the AccelerometerService are available to our compact framework application. Next, we need to instantiate this service and use it to call the UploadAccelData() function.

Open Form1.cs and add a member variable to the Form1 class which refers to the WCF service,

WCFClient_HD2.AccelerometerService.AccelerometerService accelService =
        new WCFClient_HD2.AccelerometerService.AccelerometerService();

I am going to go a bit off topic here and talk about the Accelerometer implementation on HD2. HTC does not provide an SDK for it’s devices (which is really sad) so the functionalities like Accelerometer, Proximity sensor and other custom features are not exposed to others for use. So some folks had to find out the library, reverse engineer the implementation and figure out how to use these features. The accelerometer driver is implemented in a dll called HTCSensorSDK.dll, this dll also implements a few other sensors as well. To use the accelerometer from a native application you’ll have to load this library [using LoadLibrary()], get pointers to the exported functions and call them. And from a managed application you’ll have to P/Invoke. Take a look at this post for more information on this.

Managed code to access the accelerometer on HD2 is available online and I am using the same code in this project here. Just go ahead and add HTCSensor.cs file to your project. This file implements HTCSensor class which you can use to read data from the accelerometer. The class implements StartSensor(), ReadDataFromSensor() and StopSensor() functions. Go back to Form1.cs and add two more variables to the class,

HTCSensor htcSensor = new HTCSensor();
HTCSensorData htcSensorData;

Create handlers for the Start Sensor button and uploadTimer,

private void button1_Click(object sender, EventArgs e)
{
    Button btn = sender as Button;

    if (btn.Text.Contains("Start"))
    {
        htcSensor.StartSensor();
        uploadTimer.Enabled = true;

        btn.Text = "Stop Sensor";
    }
    else
    {
        htcSensor.StopSensor();
        uploadTimer.Enabled = false;

        lblXAxis.Text = "???";
        lblYAxis.Text = "???";
        lblZAxis.Text = "???";

        btn.Text = "Start Sensor";
    }
}

and,

private void uploadTimer_Tick(object sender, EventArgs e)
{
    htcSensor.ReadDataFromSensor(out htcSensorData);

    lblXAxis.Text = htcSensorData.tiltX.ToString();
    lblYAxis.Text = htcSensorData.tiltY.ToString();
    lblZAxis.Text = htcSensorData.tiltZ.ToString();           
}

The button handler controls the timer and starts and stops it. And whenever the timer fires, we read the data from the accelerometer and display it. Run this application on HD2, if you have one, and check if the values are being read from the sensor. I am guessing that this application should also work on HTC Touch Pro2 and HTC Diamond 2 as well, but I have not tested this on those devices. Now all that is left is hooking this with the WCF Service, so every time the timer function is called we call the UploadAccelData() function of the service and pass the x, y and z values to it. Add the following lines of code to the end of the uploadTimer_Tick() function,

try
{
    accelService.UploadAccelData(htcSensorData.tiltX, true,
        htcSensorData.tiltY, true,
        htcSensorData.tiltZ, true);
}
catch (Exception ex)
{
    Console.WriteLine("An exception occured while calling into the service.");
    Console.WriteLine("{0}", ex.Message);
}

And that is all, our compact framework application is ready! Lets test whether the values are being passed to the service. Go to the solution properties and select multiple start-up projects and make sure that both the ConsoleApp and WCFClient_HD2 are set to start,

multiple start-up projects

Press F5 to start both the console and the compact framework application. Make sure that you are deploying the compact framework application to the device and that the device is connected to the machine over Active Sync (Windows XP) or WMDC (Vista or Win 7). Once both applications are deployed press the “Start Sensor” button on the phone, the accelerometer data should be getting passed to the service and the console window should output the logs as follows,

console logs showin service accel data

 

Creating the Silverlight application for Windows Phone 7
Start Visual Studio 2010 Express for Windows Phone and create a new Silverlight Windows Phone project, WCFClient_WP7Emu.

sl app wp7 project creation

Add text blocks and a button to Mainpage.xaml. The application UI looks like this,

sl app running on emu

Now lets add to this project a reference to the WCF Service. Deploy the WCF service from Visual Studio 2008 and make sure that it is running, right click on the silverlight project and select “Add Service Reference..”, and in the next dialog enter the URL of the service and press Go,

sl adding reference to service

once the service is discovered enter a namespace “AccelerometerService” and press OK to add a reference to it.

Open Mainpage.xaml.cs and add the following member variables to the Mainpage class,

WCFClient_WP7Emu.AccelerometerService.AccelerometerServiceClient accelService;
DispatcherTimer dt;

Now in the Mainpage() constructor add the following lines of code after the InitializeComponent() call,

accelService = new WCFClient_WP7Emu.AccelerometerService.AccelerometerServiceClient();

accelService.DownloadAccelDataCompleted +=
    new EventHandler<AccelerometerService.DownloadAccelDataCompletedEventArgs>(accelService_DownloadAccelDataCompleted);

dt = new DispatcherTimer();
dt.Interval = new TimeSpan(0, 0, 0, 0, 100);
dt.Tick += new EventHandler(dt_Tick);

lblXAxis.Text = "???";
lblYAxis.Text = "???";
lblZAxis.Text = "???";

Here we create an instance of the WCF service and register a handler for the DownloadAccelDataCompleted event. In silverlight for windows phone the web service api’s will be called asynchronously, and when the web service function returns, accelService_DownloadAccelDataCompleted() will be called. So we will be getting the accelerometer values in this function. Also, create a dispatch timer which fires every 100ms. Pressing TAB while creating the handlers for DownloadAccelDataCompleted and dt.Tick event will also create the function definitions for the handlers,

void accelService_DownloadAccelDataCompleted(object sender, AccelerometerService.DownloadAccelDataCompletedEventArgs e)
{

}

void dt_Tick(object sender, EventArgs e)
{

}

Add a handler for the button “Start reading data from web service”,

private void button1_Click(object sender, RoutedEventArgs e)
{
    Button btn = sender as Button;

    if (btn.Content.ToString().Contains("Start"))
    {
        dt.Start();
        btn.Content = "Stop reading data from web service";
    }
    else
    {
        dt.Stop();
        btn.Content = "Start reading data from web service";

        lblXAxis.Text = "???";
        lblYAxis.Text = "???";
        lblZAxis.Text = "???";
    }
}

So again, this handler just starts and stops the dispatch timer. Now fill in the handlers for dt.Tick and the DownloadAccelDataCompleted() functions as below,

void accelService_DownloadAccelDataCompleted(object sender, AccelerometerService.DownloadAccelDataCompletedEventArgs e)
{
    lblXAxis.Text = e.Result.ToString();
    lblYAxis.Text = e.y.ToString();
    lblZAxis.Text = e.z.ToString();
}

void dt_Tick(object sender, EventArgs e)
{
    accelService.DownloadAccelDataAsync();
}

So everytime the dispatch timer fires, we call the DownloadAccelData() function (the asynchronous version is created when we add a reference to the WCF service). And in the DownloadAccelDataCompleted() function we update the text blocks to display the accelerometer values.

And we are done, phew! Time to test’em all. Go to visual studio 2008 and start both the ConsoleApp and WCFClient_HD2 projects, once deployed press the “Start Sensor” button on the device. Now start the silverlight application from Visual Studio 2010 and press the “Start reading data from web service” button, and if you did everything right the accelerometer data should be read on the emulator and you should be seeing something like this,

service and sl app final

The other application which I showed in the video demo where a marble moved around on the screen of the emulator can now be easily implemented using the accelerometer values. I will not be going into the details of it. If you want to know how to implement one take a look at my other post where I have the source code of the application attached, the same logic holds here as well.

It’s been a really long post, if you have an HD2 and happen to try out the source code do let me know how it goes. And if you have any suggestions on how to make this code better please do leave a comment!

Written by Prabhu Kumar

August 1st, 2010 at 2:52 pm

Posted in Uncategorized

HTC HD2, Accelerometer and Windows Phone 7

without comments

I had an idea and after 5 hours of work I have a demo to show you guys. Check out this video below. It shows how the accelerometer data is read from an HTC HD2 and being used on the Windows Phone 7 emulator! I just finished this up today and will be posting details and the source code soon. Apologize for the bad quality of the video, I really need to get a better cam. But hey, I had to talk, record and demo all at the same time!

 

Written by Prabhu Kumar

July 31st, 2010 at 2:54 pm

Posted in Uncategorized