My first Windows Store application!

My first application for Windows Store is already published! It is a very simple application but now I know the complete process to publish an application on Windows Store.

The application is localized, at the moment available in English and Spanish. More Localization details.

image

I have developed this application before for Windows Phone.  I used a Portable class library to implement the Business Logic of the application – Models and Common classes.  The Views and View Models are contained in different platform specific projects (Windows 8.1 + Windows Phone 8) . More details here.

These are a couple of screenshots of the Application:

WindowsClockimage

It is optimized to run on PCs and Tablets with Windows 8.1. You can execute it in full screen or snapped mode. More details here.

Snapped mode

image

Tablet simulator

image

I will publish a small guide with the requirements to publish an application on Windows Store soon, the process is easy and very good explained, but there are some stuff to prepare: an email contact, privacy policy link, application screenshots, etc.!

Advertisements

Windows 8.1 – Localization

Today I want to share how I localized my Windows Store application, very easy! Localization can also be implemented using “Resources File (.resw)” files. I will try it soon but first I wanted to implement a solution using my already existing resx files.

To test the developing process for Windows Store and Windows Phone I am using this project structure:

projects

All localization terms are already in a portable class library, so that they are share between the Windows Phone and Windows 8 applications.

image

The terms are contained in “resx” files:

  • AppResources.resx (default app language, English)
  • AppResources.es-ES.resx  (Spanish)
  • AppResources.fra.FR.resx (French)

These files contains a list of string properties that we can create be created easily using the editor:

image

Once the project is compiled a class “AppResources” with a property of type string with each entrance of the table is created. The value of the string is resolved using the resx corresponding to the current language of the UI Thread.

There are several ways to use this resources files in XAML, I wanted to use them with the support of IntelliSense, with my solution it is possible to define a common Localization Provider on my App.xaml that uses the resources files contained by the portable class library: Continue reading

Windows 8.1 – Application life-cycle

Windows 8.1 keeps in memory the status of an application when the user sends it to background. Although the application’s threads are frozen after about 10 seconds, the application status is kept in memory until the OS runs out of resources.

When the OS needs resources the application could be removed from memory and if this happens the status is lost.

Understanding the possible status of the application and the related events helps to create a better user experience.
e.g.: Serializing the application status to disk when it’s suspended to recover it later.

This diagram describes the life cycle of a Windows 8.1 application.

Windows 8.1 App Lifecycle

Windows 8.1 App Lifecycle

References:

Windows 8.1 – Screen Mode Detection

During the development of my Windows Store application I faced out that is not that easy to detect the current screen mode to adjust consequently the layout.

These are the different screen modes available in Windows 8:

  • Portait orientation.
  • Landscape orientation, Full Screen.
  • Landscape orientation, Snapped. Sharing the screen with other applications, see the next image as an example.

Windows 8 - Screen Sharing

When the application is sharing the screen with other applications it is also important to distinguish between having a big portion of the screen or not:

smallPortionScreen

In Windows 8 it was easier to detect the screen mode:

private void WindowSizeChanged(object sender, WindowSizeChangedEventArgs e) {
    // Get view state
    ApplicationViewState currentViewState = ApplicationView.Value;

    if (currentViewState == ApplicationViewState.FullScreenLandscape) {
       // Full screen Landscape layout
    }
    else if (currentViewState == ApplicationViewState.FullScreenPortrait) {
       // Full screen Portrait layout
    }
    else if (currentViewState == ApplicationViewState.Filled) {
       // Filled layout
    }
    else if (currentViewState == ApplicationViewState.Snapped) {
       // Snapped layout
    }
}

But in Windows 8.1 the ApplicationView is deprecated, developers can only know if the screen is in Landscape or Portrait. I implemented a helper class called ScreenManager to get the current screen mode, this class has also an Event to notify when the screen mode changed:

These are the Screen Modes that I defined: Continue reading

Windows 8.1 – Data Persistance

Windows Store applications can persist runtime state, user preferences, and other settings using different mechanisms:

  • Local: Persistent data that exists only on the current device.
  • Roaming: Data that exists on all devices on which the user has installed the app.
  • Temporary: Data that could be removed by the system at any time.
var localSettings = ApplicationData.Current.LocalSettings;
var roamingSettings = ApplicationData.Current.RoamingSettings;
var tempFolder = ApplicationData.Current.TemporaryFolder;

In this post I will share my helper class to store objects using the LocalSettings container.

One problem I found when I tried to save an object to the LocalSettings is that it only supports the following types:

UInt8, Int16, UInt16, Int32, UInt32, Int64, UInt64, Single, Double
Boolean
Char16, String
DateTime, TimeSpan
GUID, Point, Size, Rect
ApplicationDataCompositeValue

For the application that I am working on I needed to store an instance of my settings data class, this class was already prepared for serialization. After playing around a little bit I found an easy solution implementing a helper class that serializes my object to XML and saves it as string.

StorageManager.cs

using Windows.Storage;

namespace WindowsStore.Common.Storage
{
    public class StorageManager
    {
        /// <summary>
        /// Initializes a new instance of the  <see cref="StorageManager" /> class.
        /// As the LocalSettings is divided in containers the constructor needs the key of the container to use.
        /// </summary>
        /// <param name="containerKey">The key.</param>
        /// <param name="isRoaming">if set to <c>true</c> [is roaming].</param>
        public StorageManager(string containerKey, bool isRoaming)
        {
            if (isRoaming)
            {
                InitializeRoamingAppContainer(containerKey);
            }
            else
            {
                InitializeLocalAppContainer(containerKey);
            }
        }

        /// <summary>
        /// Determines whether the local storage contains an object associated to the specified key.
        /// </summary>
        public bool Contains(string key)
        {
            return AppSettingsContainer.Values.ContainsKey(key);
        }

        /// <summary>
        /// Saves the specified object associated to the specified key.
        /// </summary>
        public void Save(string key, object value)
        {
            var serializedValue = XMLSerializer.SerializeToString(value);

            if (AppSettingsContainer.Values.ContainsKey(key))
            {
                AppSettingsContainer.Values[key] = serializedValue;
            }
            else
            {
                AppSettingsContainer.Values.Add(key, serializedValue);
            }
        }

        /// <summary>
        /// Loads an object associated to the specified key.
        /// </summary>
        public T Load<T>(string key)
        {
            if (AppSettingsContainer.Values.ContainsKey(key))
            {
                return XMLSerializer.DeserializeFromString<T>(AppSettingsContainer.Values[key].ToString());
            }

            return default(T);
        }

        /// <summary>
        /// Removes the object associated to the specified key.
        /// </summary>
        public bool Remove(string key)
        {
            if (AppSettingsContainer.Values.ContainsKey(key))
            {
                return AppSettingsContainer.Values.Remove(key);
            }
            return false;
        }

        #region privates

        /// <summary>
        /// Initializes a roaming application container.
        /// </summary>
        /// <param name="containerKey">The container key.</param>
        private void InitializeRoamingAppContainer(string containerKey)
        {
            // todo RoamingQuota
            if (!ApplicationData.Current.RoamingSettings.Containers.ContainsKey(containerKey))
            {
                ApplicationData.Current.RoamingSettings.CreateContainer(containerKey,
                    ApplicationDataCreateDisposition.Always);
            }

            this.AppSettingsContainer = ApplicationData.Current.RoamingSettings.Containers[containerKey];
        }

        /// <summary>
        /// Initializes a local application container.
        /// </summary>
        /// <param name="containerKey">The container key.</param>
        private void InitializeLocalAppContainer(string containerKey)
        {
            if (!ApplicationData.Current.LocalSettings.Containers.ContainsKey(containerKey))
            {
                ApplicationData.Current.LocalSettings.CreateContainer(containerKey,
                    ApplicationDataCreateDisposition.Always);
            }

            this.AppSettingsContainer = ApplicationData.Current.LocalSettings.Containers[containerKey];
        }

        /// <summary>
        /// Gets or sets the application settings container.
        /// </summary>
        private ApplicationDataContainer AppSettingsContainer { get; set; }

        #endregion

    }
}

XMLSerializer.cs

using System.IO;
using System.Xml.Serialization;

namespace WindowsStore.Common.Storage
{
    public static class XMLSerializer
    {
        /// <summary>
        /// Serializes an object to string using XML.
        /// </summary>
        /// <param name="obj">The object.</param>
        public static string SerializeToString(object obj)
        {
            XmlSerializer serializer = new XmlSerializer(obj.GetType());
            using (StringWriter writer = new StringWriter())
            {
                serializer.Serialize(writer, obj);
                return writer.ToString();
            }
        }

        /// <summary>
        /// De-serializes an object from XML string.
        /// </summary>
        /// <typeparam name="T">Type of the object to deserialize</typeparam>
        /// <param name="xml">The XML.</param>
        public static T DeserializeFromString<T>(string xml)
        {
            XmlSerializer deserializer = new XmlSerializer(typeof(T));
            using (StringReader reader = new StringReader(xml))
            {
                return (T)deserializer.Deserialize(reader);
            }
        }
    }
}

References:

Cross-platform App: Windows 8 + Windows Phone

The goal is to develop an application for Windows Store and Windows Phone maximizing code sharing.

We will need at least three projects:

  • ChessClock.Core: The logic and all common code and helpers the application can share, a Portable Class Library Project.
  • ChessClock.WindowsPhone: Windows Phone application project referencing the ChessClock.Core
  • ChessClock.WindowsStore: Windows Store application project referencing the ChessClock.Core

This is the current projects diagram:

projects diagram

Microsoft recommends to put ViewModels in the Portable Class Library, see Share functionality using Portable Class Libraries.

I prefer to put it together with the view because in my opinion view models should be only the glue between the view and the model, viewmodel should adapt the model to the view, and view models cannot contain logic but could contain for example a code that ask something to the user using a MessageBox or similar, and this is completly UI related.

Moreover this forces me to keep my viewModel as simple as possible, all the logic and data must be contained on Models.

Small part of my GameViewModel:

// Initialize commands
this.ReplayCommand = new RelayCommand(this.DoReplay);
this.PlayCommand = new RelayCommand(this.DoPlay);
this.PauseCommand = new RelayCommand(this.DoPause);
/// <summary>
/// Does the pause.
/// </summary>
private void DoPause()
{
    this.GameController.Pause();
}
 
/// <summary>
/// Does the play.
/// </summary>
private void DoPlay()
{
    this.GameController.Play();
}
 
/// <summary>
/// Does the replay.
/// </summary>
private void DoReplay()
{
    // Ask continue or start a new game
    var questionResult = MessageBox.Show(string.Empty, Core.AppResources.NewGameGamePage, MessageBoxButton.OKCancel);
    if (questionResult == MessageBoxResult.OK)
    {
        this.GameController.RestartGame();
    }
}

Difficulties found:

Converters
The interface IValueConverter is contained in different assemblies because the current culture on Windows Store App is a string and in Windows Phone is a CultureInfo object.
Microsoft decided for some reason to change this…

// Windows Store:
public object Convert(object value, Type targetType, object parameter, string culture)
// Windows Phone:
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)

So far the converters will be duplicated and located on the platform specific projects, I hope to have an idea to solve this later.

Helpers
The helpers that already exists where designed for Windows Phone, they make use of specific features as IsolatedStorage, or XNA to play sounds.
As this is not available for Windows Store a refactor of the helpers classes is necessary. The solution will be use interfaces inside the core, platform specific version will have to implement this interfaces.

References:
– Cross-Platform Development
– Portable Class Library

Windows Store – Privacy policy

This application does not collect or transmit any user’s personal information, with the exception of technical information included in HTTP requests (such as your IP address). No personal information is used, stored, secured or disclosed by services this application works with.

If you would like to report any violations of this policy, please contact us.