Friday, March 26, 2010

How to use Isolated Storage on Windows Phone 7

 

image

I wrote a little sample application that lets the user work with the isolated storage on a Windows Phone 7 device. I won’t bother you with the details of the xaml because the UI is relatively straight forward. There are only a handful of controls and they are all pretty standard. What I want to share here is the code behind that makes this application work. Besides, it’s not really the most amazing app out there, it’s just meant to show you how to work with ISO storage.

The key take-aways from this are:

1) You will need to add reference to the System.IO.IsolatedStorage assembly and add the corresponding using statement.

2) You save and retrieve the settings by calling IsolatedStorageSettings.ApplicationSettings

3) You access the setting values via their keys - IsolatedStorageSettings.ApplicationSettings[“key”]= “value”;

Hopefully this gets you started saving and retrieving data to and from a Windows Phone 7 device.

More to come… happy coding!

 

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 Microsoft.Phone.Controls;
using System.IO.IsolatedStorage;
using System.IO;

namespace Isolated_Storage
{
public partial class MainPage : PhoneApplicationPage
{
private IsolatedStorageSettings appSettings;

public MainPage()
{
InitializeComponent();

SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;

btnAdd.Click += new RoutedEventHandler(btnAdd_Click);
btnRead.Click += new RoutedEventHandler(btnRead_Click);
txtValue.TextChanged += new TextChangedEventHandler(txtValue_TextChanged);

appSettings = IsolatedStorageSettings.ApplicationSettings;

UpdateSettingsCount();
}

private void UpdateSettingsCount()
{
lblCount.Text = String.Format("App Settings Count: {0}", appSettings.Count);
}

void txtValue_TextChanged(object sender, TextChangedEventArgs e)
{
btnAdd.IsEnabled = txtValue.Text.Trim().Length > 0;
}

void btnRead_Click(object sender, RoutedEventArgs e)
{
lstItems.Items.Clear();
LoadData();
}

void btnAdd_Click(object sender, RoutedEventArgs e)
{
IsolatedStorageSettings.ApplicationSettings[(appSettings.Count + 1).ToString()] = txtValue.Text;
UpdateSettingsCount();
}

private void LoadData()
{
for (int i = 0; i < appSettings.Count; i++)
{
string entry = string.Format("Key: {0} {1}Value: {2}", i + 1, Environment.NewLine, appSettings[(i + 1).ToString()].ToString());
lstItems.Items.Add(entry);
}
}
}
}



Thursday, March 25, 2010

How to add an Application Bar to your Windows Phone 7 App

When developing Windows Phone 7 apps, it is recommended not to include custom menus within the application in order to keep apps consistent across the platform. Instead developers should use the Application Bar to place such menu-like commands.

To do this, you first add a reference to the Microsoft.Phone.Shell assembly. You then need to add your images (button icons) to the project. You need to change the Build Action to Content and set Copy to Output Directory to Copy Always.

image

Here are the best practices Microsoft recommends for the images used in the Application Bar (ooops… I’m not following all of these in my example)

  • Icon images should use a white foreground on a transparent background using an alpha channel. The Application Bar will colorize the icon according to the current style settings and colored icons can cause this effect to display unpredictably.
  • The circle displayed on each Icon Button is drawn by the Application Bar and should not be included in the source image.
  • Icon images should be 48 x 48 pixels in size. The white foreground graphic for the button should fit in a 26 x 26 area square in the center of the image so that it does not overlap the circle.
  • Do not use an Icon Button for a back button that navigates backwards in the page stack. All Windows Phones are required to have a dedicated hardware back button that should always be used for backward navigation.
  • Use Icon Buttons for the primary, most-used actions in your menu. Some actions are difficult to convey clearly with an icon. If this is the case, consider using a Menu Item instead.
  • Choose icons that have clear meanings when the Application Bar is rotated. The Application Bar automatically handles changes in screen orientation. When the device is in a landscape orientation, the menu is displayed vertically on the side of the screen. The icon buttons are rotated so that they appear upright to the user, but the order of the icons in the list is not changed. It is possible for icon meanings to be confused when this occurs, particularly if two of the icons are mirror images of each other along the Y axis.

Now to the xaml.

Add the following xaml to attribute to the phoneNavigation:PhoneApplicationPage node:

xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone.Shell"



to access the newly added dll reference.



Finally, add the following code inside the node phoneNavigation:PhoneApplicationPage node.



    <phoneNavigation:PhoneApplicationPage.ApplicationBar>
<
shell:ApplicationBar Visible="True" IsMenuEnabled="True">
<
shell:ApplicationBar.Buttons>
<
shell:ApplicationBarIconButton IconUri="/Images/thumbs up.png"></shell:ApplicationBarIconButton>
<
shell:ApplicationBarIconButton IconUri="/Images/thumbs down.png"></shell:ApplicationBarIconButton>
</
shell:ApplicationBar.Buttons>
<
shell:ApplicationBar.MenuItems>
<
shell:ApplicationBarMenuItem x:Name="menuItem1" Text="MenuItem 1"></shell:ApplicationBarMenuItem>
<
shell:ApplicationBarMenuItem x:Name="menuItem2" Text="MenuItem 2"></shell:ApplicationBarMenuItem>
</
shell:ApplicationBar.MenuItems>
</
shell:ApplicationBar>
</
phoneNavigation:PhoneApplicationPage.ApplicationBar>


 



This code sample works with the following image storage structure:



image



The result:



image



If the user clicks on the ellipses on the right side of the Application Bar, it will expand to show the menu items added.



image







If your application is setup to handle both orientations (this is the default behavior) then the menu items and the buttons will rotate appropriately when the phone’s orientation changes.



image





Wednesday, March 24, 2010

Windows Phone 7 Development: Using InputScopes

 

I went to Mix2010 this year and attended Mike Harsh’s talk on Building Windows Phone Applications with Silverlight (Part 1). After the session, I wanted to play around with InputScopes a little bit more, so I decided to try replicate the sample application he showed during the session. It is a really simple application. I figured I would post it since the presentation didn’t cover all of the implementation details.

There is a textbox where the user can type text and a listbox which contains all the available InputScopes. When the user selects an InputScope, it is applied to the textbox. This controls what the virtual keyboard looks like when the user is typing in. For instance, if the user selects the TelephoneNumber InputScope, the keyboard will look like this

image

But if he or she selects the InputScope the keyboard will look like this

image 

So, first to the xaml. This part couldn’t be simpler. Inside the content grid, I added a textbox and a listbox. I also changed the title lable to InpuScopes. That’s it for the xaml

<TextBox x:Name="txtInput" Height="50" VerticalAlignment="Top" />           
<
ListBox Height="580" x:Name="lstScope" HorizontalAlignment="Stretch" Margin="0,66,0,0" VerticalAlignment="Top" Width="460" />


And this is what it looks like. In this screenshot, the listbox is already populated, but we’ll take care of that in a minute in the code behind.



image



In the class constructor I added the bottom two lines. The first one calls a GetNames method which basically returns a list of all the names of the given Enum. The second line simply assigns an event handler to the SelectionChanged event of the listbox. This could have been done in xaml, but I arbitrarily chose to do it in code.



public MainPage()
{
InitializeComponent();

SupportedOrientations = SupportedPageOrientation.Portrait | SupportedPageOrientation.Landscape;

lstScope.ItemsSource = this.GetNames(typeof(InputScopeNameValue));
lstScope.SelectionChanged += new SelectionChangedEventHandler(lstScope_SelectionChanged);
}


Here is the implementation of the GetNames method. This will take any enumeration type and return a list of strings with all the values.


private  IEnumerable<string> GetNames(Type enumType)
{
if (!enumType.IsEnum)
{
throw new InvalidOperationException("Not an enum type");
}

List<string> nameList = new List<String>();
FieldInfo[] fiArray = enumType.GetFields();
foreach(FieldInfo fi in fiArray)
{
if (fi.FieldType.IsEnum)
{
nameList.Add(fi.Name);
}
}

return nameList;
}


Finally, I implemented the SelectionChanged event handler for the listbox. I basically get the appropriate enum value from the selected string and call the SetInputScope method which essentially sets the input scope for the textbox. That’s it. 


void lstScope_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
InputScopeNameValue val;

if (Enum.IsDefined(typeof(InputScopeNameValue), lstScope.SelectedItem))
{
val = (InputScopeNameValue)Enum.Parse(typeof(InputScopeNameValue), lstScope.SelectedItem.ToString(), true);
SetInputScope(val);
}
}

private void SetInputScope(InputScopeNameValue val)
{
try
{
txtInput.InputScope = new System.Windows.Input.InputScope()
{
Names = { new InputScopeName() { NameValue = val } }
};
}
catch (Exception)
{
//Don't do anything. This fails with some of the InputScopes // Bug?
}
}



Tuesday, March 23, 2010

Windows Phone 7 Book

Charles Petzold has written a Windows Phone 7 book and has posted a free preview here: http://charlespetzold.com/phone/index.html

Just thought I’d spread the word. More to come on Windows Phone 7 development. Happy Coding!

Wednesday, March 3, 2010

Creating a Vista "Flip 3D" Menu Using Custom Layout Panels

 

image

Silverlight provides several layout panels which can be used to layout almost any simple user interface. These layout panels are the Grid, Canvas and StackPanel. In more sophisticated user interfaces, however, these basic layout panels may not be enough. In this chapter, you will learn how to create a custom layout panel that organizes its children in a 3D stack. We will create a test application for this panel which will allow you to manipulate various properties of the panel in order to achieve different visual effects including one similar to what is seen in Windows Vista Ultimate “Flip 3D” feature (Alt+Tab while various applications or folders are open to see the “Flip 3D” feature in action) .

To begin, we need to create a new project Silverlight Class Library project in visual studio and name it CustomPanels. Now, add a class to the project and name it Stack3DPanel. Stack3DPanel needs to derive from Panel in order to inherit some of the properties and methods common to all layout panels. The most important of these is the ‘Children’ property which contains all the visual elements to be arranged by the panel. Next, we will add the dependency properties needed to manipulate the way the panel will layout its children.

Define Dependency Properties

Whenever creating properties on custom Silverlight classes, you should consider making those properties dependency properties. Although there are numerous reasons to create them as dependency properties, the most compelling reasons are arguably that dependency properties can support animations, styling and data binding. The dependency properties we will create for the Stack3DPanel are the DepthOffset, HorizontalOffset, VerticalOffset, SkewYAngle and Blur properties.

Before creating the dependency properties, we need to create a static event handler which will execute whenever any of the dependency properties’ values change. Whenever a dependency property value changes, we want to rearrange the children in the panel accordingly. To do so, we simply call the InvalidateArrange method available to us because we derived from the Panel class. Notice we cannot directly access the panel’s InvalidateArrange method by calling this.InvalidateArrange() because this method is a static method. However, the DependencyObject parameter contains a reference to the panel. We can therefore access it as a Stack3DPanel to get to the InvalidateArrange method.

image

The DepthOffset property specifies the depth between items within the panel. This correlates to the projected location of the item relative to the z axis. The greater the DepthOffsett, the greater the distance between objects in the panel. Consequently, the items in the panel will appear to get closer to the user as the DepthOffset increases.

image

Note, the Stack3DPanel arranges its children in a Last In First Out (LIFO) fashion. In other words, the first item inserted into the panel is placed at the bottom of the stack and all successive items will be placed on top of that. To add the DepthOffset property, we need to add a public static dependency property and a public property to access it. This pattern will be repeated for all the dependency properties we will create for this panel.

In order for the Silverlight property system to use the dependency property, we must follow the naming conventions it defines. Dependency properties themselves have unique basic names (DepthOffset). When creating the identifiers for those properties, the basic name is combined with the suffix Property (DepthOffsetProperty). When defining the property’s identifier, we register the dependency property by calling the static Register method of the DependencyProperty class. We will provide 4 parameters for this method. The first is the basic name of the property (i.e. DepthOffset). The second is the data type of that property. The third parameter identifies the type of the class registering the dependency property which in this case is Stack3DPanel. The final parameter is of type PropertyMetaData. This last parameter ultimately identifies what event handler to execute whenever the value of that dependency property changes. In this implementation, we want the same method to be executed whenever any of our dependency properties change, so instead of defining a new PropertyMetaData object within the Register method call (which is typically done), we will define a private variable of type PropertyMetaData which will point to the OnLayoutPropertyChanged event handler.

image

After we have created the property identifier, we can create the property which simply sets/gets the appropriate dependency property value from the Silverlight property system by calling get/set value for the appropriate property identifier.

public double DepthOffset

image

For the following dependency properties, we follow this same pattern; define the identifier by registering and then the property with a getter and setter for which access the registered dependency property.

The HorizontalOffset property specifies the amount of horizontal space between items within the panel.

image

First, we register the dependency property.

image

And then we define the HorizontalOffset property.

image

The VerticalOffset property specifies the amount of vertical space between items within the panel.

image

First, we register the dependency property.

image

And then we define the VerticalOffset property.

image

The SkewYAngle property specifies the angle by which all the items within the panel are skewed along the y axis to create various visual effects.

image

First, we register the dependency property.

image

And then we define the SkewYAngle property.

image

Lastly, Blur property specifies if a blur effect is applied to the items within the panel giving the illusion of loss of focus as the individual items are further away from the user.

image

Firs, we register the dependency property.

image

And then we define the Blur property.

image

Implement Overrides

Now it’s time to work on the heart of the Stack3DPanel. Whenever creating custom layout panels, the two most important methods that you must override are MeasureOverride and ArrangeOverride. We’ll start by implementing the MeasureOverride method.

image

MeasureOverride method first calls the Measure method for each child element. This call is necessary for the child element to calculate its DesiredSize property, which is later used in the ArrangeOverride method. The method then simply returns the availableSize it originally provided.

As its name suggests, the ArrangeOverride method is responsible for placing the children of the panel in their appropriate locations. In essence, this method contains all the logic which causes the panel to arrange its children in a 3D stack formation. While iterating through all its children, the ArrangeOverride method first center aligns each child element both vertically and horizontally. Second, a BlurEffect is applied to the children if the Blur property is set to true and if the current child element is not the first in the list. We do not want the first child element blurred because it appears in front of all the other elements. The appropriate visual effect is for those that are further back to appear blurred while the ones in front appear more focused. Then, the elements are placed on the panel. This is done by calling the child.Arrange method. Initially, all the children are placed in the same location. A series of projections and a transforms are then applied to the children according to their relative position to achieve the appropriate visual effect. First, a SkewTransform is applied with the AngleY set to the value in the SkewYAngle property as a RenderTransform. Finally, a PlaneProjection is applied to each child element. Where LocalOffsetZ, LocalOffsetX and LocalOffset Y are set to i*DepthOffset, i*HorizontalOffset and i*VerticalOffset respectively. At the conclusion of the method, the finalSize value passed in as a parameter is returned. This is typically done in most custom panel implementations. Note: when the panel is rendered, the last child element will appear in the front of the stack (closest to the user) and the first child element will appear in the back (furthest from the user).

image

Define Operations

One feature we will add to this custom panel is the ability to interact with it. We want to allow users to cycle through the items in the stack panel by popping the element on top off the stack and pushing it to the bottom of the stack allowing users to easily flip through the children in the panel. To do this, we must implement the Push, Pop, Cycle and CycleBack methods.

The panel we are creating is called a 3DStackPanel because it lays out its children in a 3 dimensional stack formation. The way we will implement that adding and removing of items from this panel, however, will more closely resemble that of a queue. Because we are calling it a 3DStackPanel, we will use name these operations Push and Pop as is typical of any stack. Note, in a traditional queue implementation, elements are added in the back of the queue and removed from the front. These operations are known as enqueue and dequeue respectively. In essence, we will implement an enqueue method and name it push and a dequeue method and name it pop.

We start with the simplest method to implement – Push. The Push method takes in an UIElement as an input parameter. This is the element that is to be inserted into the stack. We simply insert it in the front of the Children collection. Because of how the ArrangeOverride method was implemented, inserting the element in the front of the Children collection will make it appear in the back of the stack once it is rendered to the screen.

image

The Pop operation will simply remove the last child element (which is rendered at the front of the stack) from the stack and returns it. We need to check for an empty Children collection. If there are no children, the method simply returns null;

image

Now that Push and Pop have been implemented, we can add two other methods that combine these operations to allow us to flip through the stack. The cycle method will take the element appearing in the front and place it in the back. This is done by calling the Pop method and then the Push method with that same element. After we have rearranged the Children collection by calling the Push and Pop methods, we call the InvalidateArrange method to rearrange the elements on the screen.

image

The CycleBack method will do the opposite of the Cycle method. It removes the first element in the Children collection, which appears in the back of the stack, and sets it as the last in the Children collection, which in turn places it in the front of the stack when rendered. Again, once the Children are rearranged, we call InvalidateArrange to arrange the elements on the screen.

image

The last piece of functionality we will add is mousewheel interactivity. We will allow users to cycle back and forth through the elements in the panel by scrolling back and forth on the mouse wheel. To do this, we need to add a MouseWheel event handler. We then simply call the Cycle and CycleBack methods inside the event handler depending on which way the mouse wheel is rolled.

image

We have now finished implementing our custom Stack3DPanel. Now, let’s create a sample application to use this panel to arrange images in the 3D stack.

Create Sample Application

Add a new Silverlight Application project to the Visual Studio Solution and name it PictureStack. This will add two projects to the solution, the silverlight project (PictureStack) and a web project (PictureStack.Web). Paste the following XAML into MainPage.xaml located in the silverlight project to layout the user interface. In this user interface, we are placing an instance of the Stack3DPanel and using data binding to manipulate all the dependency properties we defined for it.

image

image

Now add the following code to MainPage.xaml.cs to implement the application logic. All we are doing is calling the Cycle method when the cycle button is clicked and using an OpenFileDialog to add images to the Stack3DPanel.

image

Now, run the application and experiment by changing the values of the slider to come up with different visual effects. I encourage you to also experiment with this new panel by placing images and other user interface elements such as buttons, textboxes, and other layout panels to create more sophisticated user interfaces. An interesting use of this custom panel would be to use to layout various screens of an application wizard.