WP7dev

Windows Phone 7 development tips

Monthly Archives: June 2011

Updating application tile without notifications

Updating the Application Tile is something very appreciated on Windows Phone 7, by users but also by Microsoft. Doing this using notifications can be quite a hassle as you need to write a server side application sending notifications to the phone, but if you need a simple tile update, Microsoft also added the ShellTileSchedule class which provides an easy way to handle this.

Exemple usage, this call is usually made in App.xaml.cs, in App() constructor :


ShellTileSchedule shellTileSchedule = new ShellTileSchedule();

shellTileSchedule.Recurrence = UpdateRecurrence.Interval;

shellTileSchedule.Interval = UpdateInterval.EveryHour;

shellTileSchedule.MaxUpdateCount = 168;

shellTileSchedule.StartTime = DateTime.Now;

shellTileSchedule.RemoteImageUri = new Uri(@”http://website.com/wp7icon.png”);

shellTileSchedule.Start();


Recurrence is used to set update recurrence : either once (Onetime) or at each interval of time (Interval).

Interval : update interval, only four values are supported : EveryHour, EveryDay, EveryWeek, EveryMonth

MaxUpdateCount : optional, you can set a max number of updates, if none is set, the updater will run indefinitely

StartTime : when will the schedule start

RemoteImageUri : image Uri, must be a 173×173 PNG file. Using transparency is allowed, and very advised (Microsoft loves when you use the user accent color)

Detecting connection loss / status on Windows phone 7

Knowing the status of the device connection can be very useful, displaying an error when trying to access something on the internet when the device has no connection is good practice. This is one of the points Microsoft loves to look at, especially when selecting featured applications.

There are two ways to handle this :

First is to use NetworkChange class, for example, in your App.xaml.cs constructor :

App.xaml.cs :


public App()

{

    // Standard App() content

    NetworkChange.NetworkAddressChanged += new  

        NetworkAddressChangedEventHandler(NetworkChange_NetworkAddressChanged);

}

void NetworkChange_NetworkAddressChanged(object sender, EventArgs e)

{

    if (Microsoft.Phone.Net.NetworkInformation.NetworkInterface.NetworkInterfaceType ==

    NetworkInterfaceType.None)

        Deployment.Current.Dispatcher.BeginInvoke(

            () =>

            {

                MessageBox.Show(StringLibrary.General_NetworkError);

            });

}


Or, check directly where you need to use the connection :


NetworkInterfaceType type = NetworkInterface.NetworkInterfaceType;

if (type == NetworkInterfaceType.None)

{

    // Handle error

}


This can also be used to determine what connection type is being used, simply compare NetworkInterface.NetworkInterfaceType to the possible values of NetworkInterfaceType enum.

Be very careful when using this, as when in bad cellular cover, this call can take up to 20s.


Windows Phone 7 publishing Checklist

Submitting an app to the App Hub can be quite long, and you should really prepare this carefully as any mistake can cause you a one week delay for your application publication.

Here is a list of points you should REALLY check or prepare before starting your submission :

  1. Your application must contain contact and legal information.
  2. Your XAP must be built in release, applications built in debug will be rejected.
  3. Prepare the material needed to submit your application:
    • A small mobile app tile icon (required), used in the phone Windows Phone Marketplace, 99 x 99 pixels in size. Must be a PNG without transparency.
    • A large mobile app tile icon (required), used in the phone Windows Phone Marketplace, 173 x 173 pixels in size. Must be a PNG without transparency.
    • A large PC app tile icon (required), used in the phone Windows Phone Marketplace, 200 x 200 pixels in size. Must be a PNG without transparency.
    • Application icon image : 62×62 PNG, can use transparency. Same as image included in your application.
    • Application tile image : 173×173 PNG, can use transparency. Same as image included in your application.
    • Application screenshots : 800×480 PNG, must not use transparency.
    • Application description : Text describing your application, used on marketplace to introduce your application.
    • Featured app description : Very short description used if your application gets featured on the marketplace (quite hard to achieve without having Microsoft contacts, so very optional).
    • Keywords : List of keywords, used on marketplace for search.
    • Define which category & subcategory you want your application to go on the marketplace.
  4. Your XAP must be built in release, applications built in debug will be rejected.
  5. Your application must resume normally on any page.
  6. Your application must display normally whatever theme is used (both Background and Accent color).
  7. Check that for any task making the phone not responsive for more than 3 seconds, a visual indicator such as a loading bar must be used.
  8. The application must render the first screen within 5 seconds after launch.
  9. Within 20 seconds after launch, the application must be responsive to user input.
  10. Any page displaying a popup should close this popup when Back key is pressed.
  11. Your application must not use over 90Mb of memory at any time. Many different memory use trackers can be used to check this, or by yourself using DeviceExtendedProperties.
  12. Be sure that all your text content is localized.

This list is of course not exhaustive, but most application rejection comes from these points.

Null Visibility Converter

Needing to hide an object from a view when its binded data is empty is something quite common in WP7 development, to achieve this, a very simple way is to use this converter :

NullVisibilityConverter :


public class NullVisibilityConverter : IValueConverter

{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        return value == null ? Visibility.Collapsed : Visibility.Visible;

    }

 

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

    {

        Visibility? v = value as Visibility?;

        return ((v.HasValue) || (v.Value == Visibility.Collapsed)) ? null : “”;

    }

}


Using this, you can bind your object Visibility to the value you want to check, and use the converter to hide it when it’s null :


<TextBlock Style=”{StaticResource ErrorMessageStyle}”

           Text=”{Binding CurrentErrorMessage}”

           Visibility=”{Binding CurrentErrorMessage, Converter={StaticResource

           NullVisibilityConverter}}”/>


This converter can also be adapted for Listbox to check whether its ItemsSource (List or ObservableCollection) is null or empty in order to hide the listbox and display something else

Custom Checkboxes using images

Styling Checkboxes with custom images is quite easy, simply apply this style :

ImageRadioButtonStyle Resource :


<Style x:Key=”ImageRadioButtonStyle” TargetType=”CheckBox”>

    <Setter Property=”Margin” Value=”0,0,0,0″/>

    <Setter Property=”Template”>

        <Setter.Value>

            <ControlTemplate TargetType=”CheckBox”>

                <Grid Background=”Transparent”>

                    <VisualStateManager.VisualStateGroups>

                        <VisualStateGroup x:Name=”CommonStates”>

                            <VisualState x:Name=”Normal”/>

                            <VisualState x:Name=”MouseOver”/>

                            <VisualState x:Name=”Pressed”/>

                            <VisualState x:Name=”Disabled”>

                                <Storyboard>

                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Foreground” Storyboard.TargetName=”ContentContainer”>

                                        <DiscreteObjectKeyFrame KeyTime=”0″ Value=”{StaticResource PhoneDisabledBrush}”/>

                                    </ObjectAnimationUsingKeyFrames>

                                </Storyboard>

                            </VisualState>

                        </VisualStateGroup>

                        <VisualStateGroup x:Name=”CheckStates” >

                            <VisualState x:Name=”Checked”>

                                <Storyboard>

                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Visibility” Storyboard.TargetName=”UnCheckMark”>

                                        <DiscreteObjectKeyFrame KeyTime=”0″>

                                            <DiscreteObjectKeyFrame.Value>

                                                <Visibility>Collapsed</Visibility>

                                            </DiscreteObjectKeyFrame.Value>

                                        </DiscreteObjectKeyFrame>

                                    </ObjectAnimationUsingKeyFrames>

                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Visibility” Storyboard.TargetName=”CheckRect”>

                                        <DiscreteObjectKeyFrame KeyTime=”0″>

                                            <DiscreteObjectKeyFrame.Value>

                                                <Visibility>Visible</Visibility>

                                            </DiscreteObjectKeyFrame.Value>

                                        </DiscreteObjectKeyFrame>

                                    </ObjectAnimationUsingKeyFrames>

                                </Storyboard>

                            </VisualState>

                            <VisualState x:Name=”Unchecked”>

                                <Storyboard>

                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Visibility” Storyboard.TargetName=”CheckRect”>

                                        <DiscreteObjectKeyFrame KeyTime=”0″>

                                            <DiscreteObjectKeyFrame.Value>

                                                <Visibility>Collapsed</Visibility>

                                            </DiscreteObjectKeyFrame.Value>

                                        </DiscreteObjectKeyFrame>

                                    </ObjectAnimationUsingKeyFrames>

                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty=”Visibility” Storyboard.TargetName=”UnCheckMark”>

                                        <DiscreteObjectKeyFrame KeyTime=”0″>

                                            <DiscreteObjectKeyFrame.Value>

                                                <Visibility>Visible</Visibility>

                                            </DiscreteObjectKeyFrame.Value>

                                        </DiscreteObjectKeyFrame>

                                    </ObjectAnimationUsingKeyFrames>

                                </Storyboard>

                            </VisualState>

                            <VisualState x:Name=”Indeterminate”>

                            </VisualState>

                        </VisualStateGroup>

                    </VisualStateManager.VisualStateGroups>

 

                    <Grid Margin=”{StaticResource PhoneTouchTargetLargeOverhang}”>

                        <Grid.ColumnDefinitions>

                            <ColumnDefinition Width=”32″/>

                            <ColumnDefinition Width=”*”/>

                        </Grid.ColumnDefinitions>

                        <Image x:Name=”UnCheckMark” Source=”/ProjectName;component/Resources/images/btn_radio_off.png” Visibility=”Collapsed” Margin=”0,4,0,0″></Image>

                        <Image x:Name=”CheckRect” Source=”/ProjectName;component/Resources/images/btn_radio_on.png” Margin=”0,4,0,0″></Image>

                        <ContentControl x:Name=”ContentContainer” ContentTemplate=”{TemplateBinding ContentTemplate}” Content=”{TemplateBinding Content}” Grid.Column=”1″ Foreground=”{TemplateBinding Foreground}” HorizontalContentAlignment=”{TemplateBinding HorizontalContentAlignment}” Margin=”12,0,0,0″ Padding=”{TemplateBinding Padding}” VerticalContentAlignment=”{TemplateBinding VerticalContentAlignment}”/>

                    </Grid>

                    <Grid>

                    </Grid>

                </Grid>

            </ControlTemplate>

        </Setter.Value>

    </Setter>

</Style>


This will use 2 images : /Resources/images/btn_radio_off.png and /Resources/images/btn_radio_on.png (remember to set their build action to Resource) instead of the standard checkboxes.

To apply this to any Checkbox, simply set the Style property in the XAML file :


<CheckBox x:Name=”TestCheckbox” IsChecked=”{Binding IsTest, Mode=TwoWay,

          Converter={StaticResource BoolInverterConverter}}”

          Style=”{StaticResource ImageRadioButtonStyle}”>


Navigation exception : No Fragment support right now

This bug is Wp7’s most famous bug, when navigation to the same page as the one you’re currently on, you get an exception :

How to work around this ? First, you should never need to navigate to the same page as the one you’re already on, if your application does this, you should really reconsider why (and maybe read again Microsoft guidelines for WP7 development)

To avoid any crash, a simple way is to prevent navigating to the same page, I usually do this with this piece of code inserted in App.xaml.cs :

App.xaml.cs :


// prevents crash when trying to navigate to current page

public static void NavigateTo(string url)

{

    var frame = App.Current.RootVisual as PhoneApplicationFrame;

    if ((frame == null) || (url == frame.CurrentSource.ToString()))

        return;

    frame.Navigate(new Uri(url, UriKind.Relative));

}

 


Then, instead of using :

NavigationService.Navigate(new Uri(Views/MainPage.xaml”, UriKind.Relative));

use this :

App.NavigateTo(“/Views/MainPage.xaml”);

Boolean Inverter Converter

Basic value converter, but very useful when using linked CheckBox or RadioButton :


    public class BoolInverterConverter : IValueConverter

    {

        public object Convert(object value, Type targetType, object parameter,

                              System.Globalization.CultureInfo culture)

        {

            return !(bool)value;

        }

 

        public object ConvertBack(object value, Type targetType, object parameter,

                                  System.Globalization.CultureInfo culture)

        {

            return !(bool)value;

        }

    }


Example usage : 2 Checkboxes linked to the same value, one is inverted (Value “No”). This way, when checking one box, the other gets unchecked.


<StackPanel Orientation=”Horizontal” VerticalAlignment=”Top”>

<CheckBox Style=”{StaticResource RadioButtonStyle}”

                 IsChecked=”{Binding Tested, Mode=TwoWay}”>

             <TextBlock Margin=”10,0,0,0″ FontWeight=”Bold” FontSize=”24″

Text=”{Binding StringLibrary.Tested_Yes, Source={StaticResource LocalizedStrings}}”/>

       </CheckBox>

       <CheckBox Style=”{StaticResource RadioButtonStyle}”

                 IsChecked=”{Binding Tested, Mode=TwoWay,

                            Converter={StaticResource BoolInverterConverter}}”>

             <TextBlock Margin=”10,0,0,0″ FontWeight=”Bold” FontSize=”24″

Text=”{Binding StringLibrary.Tested_No, Source={StaticResource LocalizedStrings}}”/>

       </CheckBox>

</StackPanel>


One of the known types provided to the serializer via ‘knownTypes’ argument was invalid because it was null.

When using multiple projects in the same solution where your main project references data types declared in another project or assembly, you may encounter crash when getting out of tombstoning.

For example in this project :

Project overview

Class1.cs :


public class Class1

{

    public String str { get; set; }

}


MainPage.xaml :


public MainPage()

{

    InitializeComponent();

    ClassLibrary.Class1 test = new ClassLibrary.Class1() { str = “test” };

    var store = PhoneApplicationService.Current.State;

    store[“test”] = test;

}


If your MainPage.xaml or App.xaml saves any object of type Class1 to PhoneApplicationService.Current.State, when getting back from tombstone, you will get an Exception :

One of the known types provided to the serializer via ‘knownTypes’ argument was invalid because it was null. All known types specified must be non-null values.

The reason behind this is quite simple, yet hard to find the first times you run through it. When going to tombstone mode, WP7 serializes the current application state, when getting back from it, serialized state is deserialized and loaded back into memory. But when using data types from another project, WP7 tries to deserialize data before loading other assemblies data types. This explains the exception : Class1 is not a known type when it tries to get deserialized.

How to work around this bug ? Quite easily. We’re lucky enough that in App.xaml.cs, the constructor (App()) gets called before the Application State is deserialized. All we have to do is to force the framework to create an object from ClassLibrary :

App.xaml.cs


public App()

{

    ClassLibrary.Class1 dummy = new ClassLibrary.Class1();

    dummy.str = “”;


By doing this, the framework creates an instance of the desired class before deserializing the application state. Thus, the assembly defining your type is loaded, and the exception disappear. In release mode, you need to add the second line (dummy.str = …), assigning a value to one of your class attributes, to avoid your statement from being completely removed by compiler optimizer.

This is based on Windows Phone 7.0 framework, I hope this bug will get fixed in later versions and this workaround won’t be needed any more.

You can get the project used to reproduce this bug here.