metadevblog

Windows Phone 7 App Development

Annoying IsReadOnly bug

leave a comment »

While fixing the security flaw I encountered in WP7.5 FAS I bumped into another annoying issue.

I fixed the FAS issue by hiding the password from view until you drag your finger over it.  When the TextBox has focus the password is displayed as soon as you move away it reverts to showing *********.  Neat and clean!

However the mouse over event can also turn into a Tap event and this causes the WP7 UI to show the on screen keyboard and start editing which is just a UI mess, as all the users is really trying to do is view the information and not change it.  Worse still – quite often the password is shown as ********* for editing!

In order to keep the UI clean I simply set the TextBox to have IsReadOnly=”True” and then the keyboard does not appear.  All seems good – the password is shown when the finger is dragged over it and the UI only drops into edit mode when the user wants to make a change by pressing the Edit button on the toolbar. 

But then during testing my App would sometimes crash when resuming from FAS suspension.  It would show ‘Resuming…’ on the screen and never actually resume…

It took quite a while to establish that it was the IsReadOnly=”True” setting that was causing the problem.

I suspected I could fix it by removing the focus when the App was deactivating but didn’t know how so was pleasantly surprised when the excellent Richard Woo pointed me to the solution when I posted the bug on the App Hub Developer Forum.

I dropped the code into place and the issue is resolved.

public NewItem()
{
    InitializeComponent();
    PhoneApplicationService.Current.Deactivated += new EventHandler<DeactivatedEventArgs>(Current_Deactivated);
}
/// <summary>
/// Handler to remove focus from a TextBox that is read only.  This cures
/// the exception that occurs when resuming.
/// </summary>
void Current_Deactivated(object sender, DeactivatedEventArgs e)
{
    var focusedElement = FocusManager.GetFocusedElement();
    if (focusedElement is TextBox)
    {
        if ((focusedElement as TextBox).IsReadOnly == true)
        {
            this.Focus();
        }
    }
}   
Advertisements

Written by metadevblog

February 13, 2012 at 7:28 pm

Posted in Uncategorized

Security Flaw in WP7.5

leave a comment »

I came across a security flaw in what is a neat feature in WP7.5 – I am talking about Fast Application Switching (FAS).

FAS is quite simple – press the Start button while running an App and it switches to the background.  Press and hold the back button and all the Apps in the background are displayed as a scrollable list. Touch an App and its brought back to the front.  All quite neat and useful.

However it is flawed because when the App is switched a screen shot of whatever was on the screen at the time is displayed as the background image like this:

FAS_screen

This screenshot is not that clear but ThisIsMyPassword is clearly visible!

Microsoft are aware that this is an issue and have argued that it is the users responsibility to use the phone appropriately and  keep data secure but this is a cop out in my opinion.  FAS is pretty transparent to the user – I wasn’t even aware of it when I upgraded my phone from WP7.

As an App author I have a responsibility to my users for keeping the data they have entrusted to my App as secure as possible.  I have gone to considerable effort in Master Key to ensure that the password data is secure under as many different user scenarios as possible.

In the original WP7 OS when the Start button was pressed the foreground App is closed using a process called tomb-stoning.  The App is given a chance to saved its current state prior to being shut down.  When the back button is pressed the App is restored back to the screen that was in operation.

The state management process is handled with OnNavigated events and it is the App developers responsibility to save/load the state in the event handlers.  It’s a bit of a hassle to handle tomb-stoning because it is a snapshot of where the user is at the time and cannot really show how the user got into that state automatically.  It falls on the App developer to provide additional data so that on resumption the App comes back to a working state.

In Master Key version 2.0 written with WP7 in mind when the App is resumed from tomb-stoning it returns to the login screen forcing the user to re-enter the master key password and reload the encrypted data from isolated storage.

When FAS is invoked the same tomb-stoning process is used but as a developer I don’t get a chance to control the screenshot that is taken as there is no specific API and no chance to influence what it going to be taken as screen grab occurs before the OnNavigated event is invoked.

The only solution is to ensure that the screen is maintained in a safe state so that the screen shot, whenever it occurs, will also be safe.  I implemented a solution by catching the MouseEnter/MouseLeave events and only displaying the password as the user swipes over the password box.  As soon as the mouse leaves the password box it is hidden again.

This code example which is hooked into the password box event handlers shows the password as asterisks and then displays the actual password as soon as the MouseEnter is triggered.  I had to catch the Tap event as well, as it catches and prevents the MouseLeave event from firing which would otherwise leave the password on display.

private string Password="MyCurrentPassword";
private string PasswordHidden = "".PadLeft(Password.Length, '*');
private void OnMouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
{
    textBoxPassword.Text = Password;
}

private void OnMouseLeave(object sender, System.Windows.Input.MouseEventArgs e)
{
    textBoxPassword.Text = PasswordHidden;
}

void OnTap(object sender, System.Windows.Input.GestureEventArgs e)
{
    textBoxPassword.Text = PasswordHidden;
}

The result looks like this:
 

view_entry_password

Ideally Microsoft will provide an API that would let the developer substitute another screenshot in place of the default – the splash screen for example.  Until then its up to us to jump over a couple of hurdles to keep the data secure from prying eyes!

Written by metadevblog

February 4, 2012 at 8:13 pm

Posted in Uncategorized

Long List Selector (Jump List) Example

with 8 comments

I am developing an App that will require the Long List Selector (LLS) functionality that is demonstrated in the  WP7 People selector.  The LLS also provides a good UI for breaking up even modest sized lists in to easy on the eye groups.

The Windows Phone Toolkit on Codeplex (http://silverlight.codeplex.com/releases/view/75888) provides a LLS but there is no documentation to explain how to use it.

The LLS is not a simple control – there is a fair amount of setup and code required before it will work, however I’ve learnt a lot and am quite pleased with the result.

I have replaced the standard List control in my Master Key application with a LLS but have created a cut down version of the App just to focus on using LLS.  I’ve kept the Transitions code in place as well from the previous post.

Before going into the details of LLS I should explain some of the other code that is in the example I’m going to use.

I make extensive use of XML in my applications when working with data, I find the ease with which I can create a robust and arbitrarily complex data model using XML documents far outweighs any disadvantages. Linq for XML is brilliant to work with and over the years I’ve created a set of simple helper extensions which simplify the extraction of values from XML Elements and Attributes.

I always add a copy of XElementHelpers.cs to my projects when I’m using Linq as it removes some of the pain involved when the XML is missing elements. It is a helper class which adds some useful methods for retrieving the values of XML Elements and Attributes. The most commonly used being .ToStringNull() which will return either the Element value or an empty string, however it also returns an empty string even if the Element does not exist (is null).

I’ve also learnt that using a Data Access Layer (DAL) even for small projects brings long term benefits in terms of maintainability and extensibility so my code examples will be slightly more complex as a result.

I’ve put the source for the project here: www.metadev.co.uk/Downloads/PhoneAppLLS.zip please feel free to download and use it.

I have included enough code in the example, which is a cut down version of my Master Key App, to demonstrate the full lifecycle for list management allowing entries to be displayed, selected and edited as well as being able to add and delete entries.

The idea behind the Master Key App is pretty simple – it allows the user to keep a list of keys, passwords and other info in an encrypted form on the phone.  A single ‘master key’ decrypts the information giving access to the entries.  I’ve called the list a Vault which is made up of individual Vault Entries so you will see plenty of references to Vaults in the code!

For this sample I have removed the encryption and much of the other persistence code as it distracts from the LLS.

LLSScreenShot

The LLS groups items under a title.  The title can be arbitrary but for this example I have stuck to grouping the entries based on the first character of the caption.  The classification is however completely open and any parent can be defined.

The Vault is maintained in the DAL as a sorted Dictionary of <Caption, VaultEntry> pairs.  In the previous version these entries where then simply dropped into a standard ListBox.  Sorting is not something that comes for free with either the ListBox or the LLS (or even the Dictionary object for that matter) so maintaining the sorted list is part of the DAL.

        public void SortEntries()
        {
            try
            {
                // sort the keys - Silverlight Dictionary does not have a sort option
                string[] array = new string[VaultEntries.Keys.Count];
                VaultEntries.Keys.CopyTo(array, 0);
                List<string> list = new List<string>(array);
                list.Sort();

                // now recreate the dictioanry                
                Dictionary<string, VaultEntry> sortedEntries = new Dictionary<string, VaultEntry>();
                VaultEntry entry = new VaultEntry();

                foreach (string key in list)
                {
                    VaultEntries.TryGetValue(key, out entry);
                    sortedEntries.Add(key, entry);
                }

                VaultEntries = sortedEntries;
            }
            catch
            {
                throw;
            }
        }
 
A generic Group class is used to hold the entries for the LLS.  The Group class looks like this:

The Group class has two principle properties, a Title which provides the group heading and a List of entries which provide the rest of the group content.

    /// <summary>
    /// Generic Group class which has a string Title and a generic list of items
    /// that are related to the title - for example the Title could be 'k' and then
    /// all the items could have entry such as a persons surname that being with 'k'
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class Group<T> : IEnumerable<T>
    {
        /// <summary>
        /// Group title - this provides the jump list titles
        /// </summary>
        public string Title
        {
            get;
            set;
        }

        /// <summary>
        /// List of items in the group
        /// </summary>
        public IList<T> Items
        {
            get;
            set;
        }

        /// <summary>
        /// True when there are items - it's used primarily to create the tiles in the jump list
        /// to indicate visibly where items exist
        /// </summary>
        public bool HasItems
        {
            get
            {
                return Items.Count > 0;
            }
        }

        /// <summary>
        /// This is used to colour the tiles - greying out those that have no entries
        /// </summary>
        public Brush GroupBackgroundBrush
        {
            get
            {
                return (SolidColorBrush)Application.Current.Resources[(HasItems) ? 
                            "PhoneAccentBrush" : "PhoneChromeBrush"];
            }
        }

        /// <summary>
        /// Group constructor
        /// </summary>
        /// <param name="name"></param>
        /// <param name="items"></param>
        public Group(string name, IEnumerable<T> items)
        {
            this.Title = name;
            this.Items = new List<T>(items);
        }

        /// <summary>
        /// Test for Title equality (and that object exists)
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj)
        {
            Group<T> that = obj as Group<T>;
            return (that != null) && (this.Title.Equals(that.Title));
        }

        /// <summary>
        /// When overriding Equals the GetHashCode has to also be overridden
        /// </summary>
        /// <returns></returns>
        public override int GetHashCode()
        {
            return this.Title.GetHashCode();
        }

        /// <summary>
        /// Item collection enumerator
        /// </summary>
        /// <returns></returns>
        public IEnumerator<T> GetEnumerator()
        {
            return this.Items.GetEnumerator();
        }

        /// <summary>
        /// Item collection enumerator
        /// </summary>
        /// <returns></returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.Items.GetEnumerator();
        }
    }

 

The properties HasItems and GroupBackgroundBrush are primarily used when displaying the jump list:

LLSJumpList

A requirement for the LLS list is for the list elements to be IEnumerable and this is provided with the methods at the bottom of the class.

As the Group class is generic it needs to be solidified to provide the specific functionality needed for this application and this is achieved with this class:

    /// <summary>
    /// This class is responsible for building the specific a-z jump list. If grouping is required around
    /// a different classification then another implementation has to be written.
    /// This implementation is efficient in that there are only two loops through the data, one to create the
    /// Group list with the specific titles and then a second pass through the data itself.
    /// </summary>
    public class AGroupedVaultEntry : List<Group<VaultEntry>>
    {
        private static readonly string Groups = "#abcdefghijklmnopqrstuvwxyz";

        /// <summary>
        /// Build and return a Grouped list based on the current VaultEntry Dictionary
        /// </summary>
        public AGroupedVaultEntry()
        {
            DataAccessLayer DAL = (Application.Current as App).DAL;

            // create the groups by simply iterating over the group string
            foreach (char c in Groups)
            {
                Group<VaultEntry> g = new Group<VaultEntry>(c.ToString(), new List<VaultEntry>());
                this.Add(g);
            }

            List<Group<VaultEntry>> list = this;

            // now iterate over the VaultEntries and add them to the appropriate group
            foreach (VaultEntry vaultEntry in DAL.VaultEntries.Values)
            {
                // get the first char (lower case) of the entry
                string c = VaultEntry.GetCaptionGroup(vaultEntry);
                
                // calculate the index into the list
                int index = (c == "#") ? 0 : c[0] - 'a' + 1;

                // and add the entry
                list[index].Items.Add(vaultEntry);
            }
        }
    }

 

This class is designed to create and return a List of Group VaultEntries with each Group header being a letter of the alphabet (plus # for all others). It will then populate the Group Items with the actual VaultEntries based on their group Title (a-z) – this association is made using the GetCaptionGroup which has been added specifically to the VaultEntry class for this purpose:

/// <summary>
/// Get the first letter of the caption or #
/// </summary>
public static string GetCaptionGroup(VaultEntry Current)
{
    char key = char.ToLower(Current.Caption[0]);
    if (key < 'a' || key > 'z')
    {
        key = '#';
    }
    return key.ToString();
}
 
Because the Vault Dictionary is already sorted by the Caption then the code for adding the appropriate 
entries is simplified and each VaultEntry can be added to the list in a single pass.
 
So far all the code discussed has been written to provide suitable data for the LLS, the final part is to set up the control itself so that it can make use of it.
 

The LLS can be used as a standard list quite simply, this XAML will display the Vault Entries without any header decoration:

<toolkit:LongListSelector VerticalAlignment="Stretch" HorizontalAlignment="Stretch" 
                          Margin="6,6" 
                          Name="longListSelectorVaultEntries" 
                          IsFlatList="False"  IsBouncy="True"
                          Loaded="OnLoaded" SelectionChanged="OnSelectionChanged">

    <toolkit:LongListSelector.ItemTemplate>
        <DataTemplate>
            <Grid Background="Transparent">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Image Width="55" Source="/Toolkit.Content/LOCKED.png" 
                       VerticalAlignment="Top"/>
                <StackPanel Grid.Column="1"  VerticalAlignment="Top">
                    <TextBlock Text="{Binding Caption}" 
                               Style="{StaticResource PhoneTextLargeStyle}" 
                               Margin="0,8,0,0"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </toolkit:LongListSelector.ItemTemplate>

</toolkit:LongListSelector>

 

The TextBlock.Text is bound to the Caption in the Vault Entry it is currently iterating over.  I’ll show later that multiple items can be displayed here.

There are two events defined – OnLoaded which is used to fetch and display the current Vault Entry list and OnSelectionChanged which is used to capture the user selecting an entry for display/editing.

The OnLoaded event looks like this:

private void OnLoaded(object sender, RoutedEventArgs e)
{
    DataAccessLayer DAL = (Application.Current as App).DAL;

    // when the page is being resumed this event will fire but it's not
    // appropriate to display the info as we actually want to hide it.
    if (DAL.ResumeFromDeactivation)
    {
        return;
    }

    // if the key has changed then reload the value entries
    if (DAL.ListReloadRequired || longListSelectorVaultEntries.ItemsSource == null)
    {
        ShowVault();

        DAL.ListReloadRequired = false;
    }
}
 
The AGroupedVaultEntry method is called and the IEnumerable Group<> is applied to the LLS ItemsSource.
 
The SelectionChanged event simply returns the selected item as the VaultEntry object from the Group List
 
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    // edit the selected item
    VaultEntry entry = (VaultEntry)longListSelectorVaultEntries.SelectedItem;
    if (entry == null) return;

    longListSelectorVaultEntries.SelectedItem = null;

    // pass the get to NewItem so that it can be looked up
    this.NavigationService.Navigate(new Uri(string.Format("/EditEntry.xaml?type=edit&key={0}", entry.Caption), 
              UriKind.Relative));
}
 

The SelectedItem is set to null again so that it can be reselected.
 
LLSStandardList
 
In order to provide the grouping and the jump list additional DataTemplates have to be added to the XAML none of which are particularly complex:
 
<toolkit:LongListSelector VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="6,6" 
                            Name="longListSelectorVaultEntries" 
                            IsFlatList="False"  IsBouncy="True"
                            Loaded="OnLoaded" SelectionChanged="OnSelectionChanged">

    <toolkit:LongListSelector.GroupItemsPanel>
        <ItemsPanelTemplate>
            <toolkit:WrapPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </toolkit:LongListSelector.GroupItemsPanel>

    <toolkit:LongListSelector.GroupItemTemplate>
        <DataTemplate>
            <Border Background="{Binding GroupBackgroundBrush}" Width="99" Height="99" Margin="6" 
                                IsHitTestVisible="{Binding HasItems}">
                <TextBlock Text="{Binding Title}" 
                            Style="{StaticResource PhoneTextExtraLargeStyle}"
                            Margin="{StaticResource PhoneTouchTargetOverhang}"
                            Foreground="{StaticResource PhoneForegroundBrush}"                                        
                            VerticalAlignment="Bottom"/>
            </Border>
        </DataTemplate>
    </toolkit:LongListSelector.GroupItemTemplate>

    <toolkit:LongListSelector.GroupHeaderTemplate>
        <DataTemplate>
            <Border Background="Transparent">
                <Border Background="{StaticResource PhoneAccentBrush}" 
                        Width="55" Height="55" HorizontalAlignment="Left">
                    <TextBlock Text="{Binding Title}" 
                                Foreground="{StaticResource PhoneForegroundBrush}" 
                                Style="{StaticResource PhoneTextLargeStyle}"
                                VerticalAlignment="Bottom"/>
                </Border>
            </Border>
        </DataTemplate>
    </toolkit:LongListSelector.GroupHeaderTemplate>

    <toolkit:LongListSelector.ItemTemplate>
        <DataTemplate>
            <Grid Background="Transparent">
                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="Auto"/>
                    <ColumnDefinition Width="*"/>
                </Grid.ColumnDefinitions>
                <Image Width="55" Source="/Toolkit.Content/LOCKED.png" VerticalAlignment="Top"/>
                <StackPanel Grid.Column="1"  VerticalAlignment="Top">
                    <TextBlock Text="{Binding Caption}" 
                               Style="{StaticResource PhoneTextLargeStyle}" Margin="0,8,0,0"/>
                    <TextBlock Text="{Binding Identity}" 
                               Style="{StaticResource PhoneTextNormalStyle}" Foreground="DarkGray"/>
                    <TextBlock Text="{Binding OtherInfo}" 
                               Style="{StaticResource PhoneTextNormalStyle}" Foreground="DarkGray"/>
                </StackPanel>
            </Grid>
        </DataTemplate>
    </toolkit:LongListSelector.ItemTemplate>

    <!--<toolkit:LongListSelector.ListFooterTemplate>
                    <DataTemplate>
                        <Border Background="Transparent" Height="159">
                            <TextBlock Text="End..." />
                        </Border>
                    </DataTemplate>
                </toolkit:LongListSelector.ListFooterTemplate>-->

</toolkit:LongListSelector>
 
There is a lot of it but it’s pretty straight forward – I copied it pretty much verbatim from the Toolkit example code.
 
The GroupItemsPanel is used to display the Group headers as shown above.  The Orientation=”Horizontal” forces the panel items to be displayed as a horizontal list, when Vertical is used then the items are centred as a long scrolling list – useful for when there are wide group headings.  Horizontal is perfect for the a-z listing.
 
The GroupItemTemplate is used to create the individual items that will be shown in the Panel and is bound to the HasItems method in the Group class.  The Background is bound  GroupBackgroundBrush in the same class (it makes use of HasItems internally to choose the appropriate colour) as is the Title (Title in turn has been set previously from the Vault Entry Caption).
 
The GroupHeaderTemplate is used to create the heading for each Group that has items associated with it, empty groups are omitted.
 
That’s it! I hope this explanation has been useful and that it will help you get up to speed more quickly than I was able to with LLS.
 
One final thing though – I believe there is a bug in the LLS that prevents it from showing the last group in the list correctly.  If I click on a group header to display the jump list and then click ‘w’ the display looks like this:
 
LLSLastW
 
There are another two entries below this that are not displayed – i.e when the LLS displays this last list entry it should start a couple of rows higher.  I got round this by adding a footer to the LLS:
 
<toolkit:LongListSelector.ListFooterTemplate>
    <DataTemplate>
        <Border Background="Transparent" Height="159">
            <TextBlock Text="End..." />
        </Border>
    </DataTemplate>
</toolkit:LongListSelector.ListFooterTemplate>
 

This still isn’t perfect but at least it does seem to hide the problem somewhat.

All in all the Long List Selector is a great control that adds a lot of functionality to the mundane list control.

Oh – I forgot to show that the LLS can show more than lists – you will have seen this already in the LLS in the Toolkit example.  All you need to do is add the extra info to the StackPanel:

 
<StackPanel Grid.Column="1"  VerticalAlignment="Top">
    <TextBlock Text="{Binding Caption}" 
                Style="{StaticResource PhoneTextLargeStyle}" Margin="0,8,0,0"/>
    <TextBlock Text="{Binding Identity}" 
                Style="{StaticResource PhoneTextNormalStyle}" Foreground="DarkGray"/>
    <TextBlock Text="{Binding OtherInfo}" 
                Style="{StaticResource PhoneTextNormalStyle}" Foreground="DarkGray"/>
</StackPanel>

Written by metadevblog

December 27, 2011 at 11:58 am

Posted in c#, WP7

Page Transitions

leave a comment »

This is a quick note on getting page transitions to work.  Animation is a subtle but key feature of Windows Phone apps and I wanted to experiment with the process.  It turned out to be pretty simple…

The Windows Phone Toolkit on Codeplex (http://silverlight.codeplex.com/releases/view/75888) provides some really useful components, one of which is called Transitions.

The toolkit is easy to install and is referenced in pages by adding this to the header:

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

In order to use it this XAML is added to the start of each page (just before the page layout)…

    <toolkit:TransitionService.NavigationInTransition>
        <toolkit:NavigationInTransition>
            <toolkit:NavigationInTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardIn"/>
            </toolkit:NavigationInTransition.Backward>
            <toolkit:NavigationInTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardIn"/>
            </toolkit:NavigationInTransition.Forward>
        </toolkit:NavigationInTransition>
    </toolkit:TransitionService.NavigationInTransition>
    <toolkit:TransitionService.NavigationOutTransition>
        <toolkit:NavigationOutTransition>
            <toolkit:NavigationOutTransition.Backward>
                <toolkit:TurnstileTransition Mode="BackwardOut"/>
            </toolkit:NavigationOutTransition.Backward>
            <toolkit:NavigationOutTransition.Forward>
                <toolkit:TurnstileTransition Mode="ForwardOut"/>
            </toolkit:NavigationOutTransition.Forward>
        </toolkit:NavigationOutTransition>
    </toolkit:TransitionService.NavigationOutTransition>

 

The XAML manages the animation of the page as it is entered and exited. The Mode attribute controls the animation style – in this case its called ‘Turnstyle’.

In order to make the process work the RootFrame style has to be changed in App.xmal.cs:

        private void InitializePhoneApplication()
        {
            if (phoneApplicationInitialized)
                return;

            // Create the frame but don't set it as RootVisual yet; this allows the splash
            // screen to remain active until the application is ready to render.
            //RootFrame = new PhoneApplicationFrame();
            RootFrame = new TransitionFrame();
            RootFrame.Navigated += CompleteInitializePhoneApplication;

            // Handle navigation failures
            RootFrame.NavigationFailed += RootFrame_NavigationFailed;

            // Ensure we don't initialize again
            phoneApplicationInitialized = true;
        }

That’s it!

Written by metadevblog

December 21, 2011 at 8:37 am

Posted in Uncategorized

Social Objects

leave a comment »

I went to an ‘event’ a couple of days ago organised by the cartoonist Hugh MacLeod (www.gapingvoid.com).  Hugh talked about using cartoons as Social Objects.  He asked us to bring along a social object of our own and after some thought I came up with the idea of an App as a Social Object.

I only had a spare hour on the train on the morning of the event so the App was going to be pretty simple.

Without having to give too much thought I quickly turned the invitation to the event which had arrived via an email into the ‘social object’ App.  The images and text simply being lifted and re-formatted to suit to phone.

image

image

The event was being held at 1 Alfred Place in London and in order to get there I had to walk from Euston Station so I used Bing Maps and grabbed a section of the map, suitably zoomed for my image.  I added pan and zoom so that I could move around the image and created a directions page.  I used the Bing London Street Map which is far more useful than other forms for the tiny streets in the capital.

image

I didn’t use the the WP7 Maps for two reasons, firstly I didn’t have time to learn how to make it work and secondly the phone signal can be patchy and I didn’t want to have to rely on it for the App.  Also the London Street Map is not available on the phone.

Finally I quickly created a Tile image and deployed the App to my phone.  I had a social object…

image

I showed the App to a few people at the event and the general reaction was ‘wow’, the fact that I had created it specially being the main significance as obviously the App itself is trivial.  I do however tend to forget that outside the technologists and developers that I work with; for most people software is a black art…

I’ve spent a couple of hours since refining the App to implement clipping, though the screen shots above are from the original.

Using WP7 gestures for the image Pan and Zoom on the map was pretty simple to implement but the image moved outside the bounds of the canvas I created.  In order to clip the map so that it did not overwrite the rest of the text on the screen I had to implement a clipping behaviour.  Given that the behaviour is both quite simple to implement and of such obvious benefit I am somewhat surprised that it’s not available by default.

There are quite a few clipping examples around but none of them have the elegance of this solution which implements a clipping behaviour:

http://www.pitorque.de/MisterGoodcat/post/Windows-Phone-7-Pinch-Gesture-Sample.aspx

Oh and the evening? I can’t complain – free beer is a good way to encourage positive feedback! Hugh rambled a bit and didn’t make any effort to see the audiences social objects which was a disappointment as I’m sure there would have been a lot more audience participation.

Written by metadevblog

July 27, 2011 at 7:35 am

Posted in Uncategorized

Silverlight Metro Theme

with 3 comments

The WP7 currently has a tiny market share so writing apps to target both the WP7 and the desktop using the same code base makes a great deal of sense to me.  Especially for tools such as Master Key which has as much validity (if not more) on the desktop as it does on my phone.

I picked up a copy of the Metro Theme from a project on Codeplex and copied one of the Master Key XMLA pages over.  It worked pretty well but in the end I’m left in the position of having to do a great deal of work to make the page fit into a browser window rather than the phone.

http://metrotheme.codeplex.com/

There are a number of issues.  Firstly the fonts and lines used to render on the WP7 screen look huge when viewed in normal Windows resolution; secondly the theme is incomplete and has missing features.  While all this can be fixed by modifying the theme it’s a lot of work.

Secondly, and obviously, the browser environment is significantly different to that of the WP7. The hardware back and close buttons have to be provided in Silverlight and handled in the browser. From a browser UX point of view these buttons would typically be at the top of the screen.  Handling ‘back’ is less of a problem as the browser supports this. However the browser also provides ‘forwards’ as well and the user can also pick an item from the navigation history and jump directly there, neither of which are possible in WP7.

Having experimented with directly porting the WP7 app and finding it a less than compelling outcome I searched around for the Silverlight theme to use.  After some experimentation I picked up a Window 7 theme that the Silverlight dev team released (see Tim Heuer’s blog http://timheuer.com/blog) and have used this as the basis for the Windows version.

The project template also provides a navigation framework which is really useful and this integrates into the browser navigation history providing back/forward support.

It was pretty simple to take a WP7 page and convert it to Win7, for the most part the XAML simply pasted directly and only needed to be lightly manipulated to fit.  Over the space of a couple of days I had pretty much replicated the App, however…

However, it was apparent pretty quickly that the integration into the browser navigation was not going to work, the history just kept getting bigger and worse I could jump forward when it was illogical to do so.  I spent a lot of time trying to make it work but in the end it was just too confusing from a UX point of view.  I switched it off and suddenly the navigation became a whole lot more logical as the framework is tabbed

image

The ApplicationBar in WP7 is a great little control and works really well on the phone.  It’s location at the bottom of the screen near to the where your fingers lay makes for a great UX. 

I considered briefly writing a version of this for Silverlight but decided against it as the more normal windows layout is better and the Ribbon interface is clean and well accepted.

In the end I decided that the simplest approach was to revert from having ApplicationBar based button back to a more traditional approach with the buttons embedded into the UI.  This is perfectly valid when there are so few buttons required to make the App work.

It was apparent as soon as I started to think about a Silverlight version of Master Key that combining the item selection and its content into a single page would be the best approach; so for WP7 the user is shown the Vault Entries as a list:

edit_vault

And when an item in the list is selected is is displayed on a separate screen:

edit_entry

This works really well – the UI is easy to use and quite clear in its intent.

Combining the two screens and modifying the UI slightly gives this screen:

image

Master Key on WP7 relies on the phone timeout kicking in to prevent unauthorised access, on my phone it’s set to a minute after which it will tombstone and the user has to re-enter the password to regain access to the information when the app is reactivated. 

In the browser environment this has to be done within the page by running a timer that will prevent access if there is no activity.  I’ve added a progress bar at the bottom of the screen – after 30 seconds of inactivity the page will close and revert to the login screen. Job done!

The core functionality of Master Key for WP7 has moved without change to the Silverlight version.  I’ve not had to touch a line of code in the data access layer to make it work and this includes the WCF service code (though to be fair I added the service reference to the new project and it auto-generated the appropriate code).

You don’t need to be too eagle eyed to see that the two vaults are the same – I simply loaded the demo vault into both versions of the App from the web service.

So the end result is that I now have a WP7 and Windows version of Master Key and the vault files are interchangeable between the two.  Also I now have a good idea as to how much additional effort has to be put in to convert between the two platforms.  I have a bit of work still outstanding to be able to launch the desktop version from the MasterKey service but I don’t anticipate this taking a lot of time.

One thing – I am pretty frustrated with myself for using the Windows 7 theme rather than Cosmopolitan as this is the closest the the WP7 Metro theme.  I was hoping I could simply swap themes but this failed on my first attempt to replace the Windows 7 theme. I’ll have to spend some time working this out when I have a chance.

Written by metadevblog

July 13, 2011 at 10:50 am

Posted in Master Key, Silverlight, WCF, WP7

Master Key version 2.0 published

leave a comment »

I’ve spent the last couple of months working on upgrading Master Key to version 2.0.  It’s been quite an interesting process as it makes use of the remote storage facility I have written about previously. 

I had this working in version 1.0 to allow me to save/load my data while the App was under development but it was really just prototype code.  I have added full support in this version of the App so that Load Vault and Save Vault are fully defined in the UI and perform robustly.

Master Key version 1.0 was primarily about creating a completed and fully functional App and understanding the Marketplace publishing process.  Version 2.0 rounds this out to create, what I consider, to be a really useful App that can be used day to day to remember multiple passwords; I’ve surprised myself by currently having 21 items stored.

Oh and I’ve not been disappointed with sales either, as they have lived up to my expectations of being pretty minimal.   Writing Apps for the WP7 at this time was never going to be about the money as the potential market is tiny. 

However I have my doubts about writing Apps for any platform; there have been some notable successes but for the vast, vast majority of Apps the cost of development far outweighs the money that can be generated from sales.

I chose to write Master Key because I had a well defined requirement and it’s a very widespread issue that we all pretty much share.  However it is lost amongst a mass of other competing Apps, some good but mostly crap and it’s really hard to get noticed.

When I started writing Master Key I was slightly concerned that it might be refused because it is not unique but this was quickly dispelled when I saw how many password saving Apps had been published – clearly uniqueness is not a criteria that is applied otherwise there would be thousands of ‘squatter’ Apps blocking the quality or more functional solutions.  In an ideal world the quality Apps would bubble to the top but this is not the case, first mover advantage especially with a few good reviews reduce the chances of similar Apps quite significantly.  And of course its relatively easy to ‘game’ the system by creating false accounts and/or getting mates to post positive reviews.

Without throwing money at good old fashioned marketing and advertising its hard to see how an App really stands much chance of being distinguished and as the money to be made is pretty low to start with that’s something of a fools errand.

Written by metadevblog

July 12, 2011 at 3:58 pm

Posted in Master Key, WP7