Diederik Krols

The XAML Brewer

Playing sounds in a Universal Windows MVVM app

This article describes how to play foreground and background sounds in a XAML-based Universal Windows app. I know that this sounds easy (pun intended). But I will do this while sticking to the MVVM pattern, which makes it a bit more challenging. I’m not targeting a specific framework here. The described architecture can be applied in MVVM Light, Universal Prism, Caliburn.Micro as well as in your home brewed MVVM library.

Here’s how the attached sample app looks like. It comes with two buttons that trigger a different sound effect, a switch to mute the background sound, and a button to navigate to a new page (very uncommon in a single-page app Happy):SoundsApp

What's the challenge for an MVVM solution to play sounds? Well, a universal XAML app can only make noise through a MediaElement, and that MediaElement should be part of the runtime structure of XAML objects known as the visual tree. As a result of that, only a small number of app components -the currently active Views- have access to it. In most cases however it’s the business logic in the Model or the ViewModel that knows which specific sound effect should be played at which particular moment. So the ‘Sound’ functionality should not be restricted to a some Views, but it should be generally available to all application components and component types.

In most MVVM ecosystems, this type of global functionality ends up in a so-called Service (other examples include logging, authorization, and toast notification). And so does the SoundPlayer: it’s a global service that comes with a Play method. That method has two parameters:

  • a reference to the sound effect (from a developer-friendly enumeration), and
  • a boolean indicating whether the sound should be played in the foreground (once) or in the background (in a loop).

Since a MediaElement can only play one sound at a time, the SoundPlayer is connected to two of them – one for the foreground and one for background. The background player can be disabled (muted) by the app.

Here’s an class diagram of the SoundPlayer, together with the Visual Studio solution structure. The platform specific projects for Windows 8.1 and Windows Phone 8.1 are collapsed, since they’re empty – except for the tile images. All the code is in the Shared project:

Solution

This is how everything was set up. The first challenge is to make sure that every Page of the app is decorated with two MediaElement instances. An easy way to do this, is to put these elements in the app’s root frame. This can be done through a custom style, e.g. in the App.xaml file:

<Application.Resources>
    <!-- Injecting media players on each page --> 
    <Style x:Key="RootFrameStyle"
           TargetType="Frame">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="Frame">
                    <Grid>
                        <!-- Foreground Player -->
                        <MediaElement IsLooping="False" />
                        <!-- Background Player -->
                        <MediaElement IsLooping="True" />
                        <ContentPresenter />
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Application.Resources>

Make sure that the style is applied when the app is launched, by adding an extra line of code in the standard OnLaunched method in App.xaml.cs:.

protected override void OnLaunched(LaunchActivatedEventArgs e)
{
    Frame rootFrame = Window.Current.Content as Frame;

    if (rootFrame == null)
    {
        rootFrame = new Frame();

        // Injecting media players on each page.
        rootFrame.Style = this.Resources["RootFrameStyle"] as Style;

        // ...
    }

    // ...
}

As long as you navigate within the frame, the media elements remain available. But when you programmatically switch to another root Frame, you have to make sure to apply this style to it. That’s what the navigate button in the sample app does:

var rootFrame = new Frame();
rootFrame.Style = App.Current.Resources["RootFrameStyle"] as Style;
Window.Current.Content = rootFrame ;
rootFrame.Navigate(typeof(MainPage));

Achievement unlocked: every page will always two MediaElement instances on it. We just have to make them available to the SoundPlayer service. This assignment is done in the Initialize call in the SoundPlayer class itself. Make sure to preserve the state since we might be hosted in a new frame with brand new UI elements at their default -unmuted- state:

public void Initialize()
{
    // Register media elements to the Sound Service.
    try
    {
        DependencyObject rootGrid = VisualTreeHelper.GetChild(Window.Current.Content, 0);
        var foregroundPlayer = (MediaElement)VisualTreeHelper.GetChild(rootGrid, 0) as MediaElement;
        var backgroundPlayer = (MediaElement)VisualTreeHelper.GetChild(rootGrid, 1) as MediaElement;

        SoundPlayer.ForegroundPlayer = foregroundPlayer;

        // Keep the state.
        var isMuted = this.IsBackgroundMuted;
        SoundPlayer.BackgroundPlayer = backgroundPlayer;
        this.IsBackgroundMuted = isMuted;
    }
    catch (Exception)
    {
        // Most probably you forgot to apply the custom root frame style.
        SoundPlayer.ForegroundPlayer = null;
        SoundPlayer.BackgroundPlayer = null;
    }
}

Every Page should make a call to this Initialize after loading, so I factored out the call into a common base class for all of the app’s Page-type views.

public class ViewBase : Page
{
    public ViewBase()
    {
        this.Loaded += this.OnLoaded;
    }

    protected virtual void OnLoaded(object sender, RoutedEventArgs e)
    {
        SoundPlayer.Instance.Initialize();
    }
}
public sealed partial class MainPage : ViewBase
{
    // ...
}

To make the SoundPlayer service globally accessible, it was implemented as a Singleton. A static class would not work, since property-changed notification requires an instance. In most MVVM frameworks this instance would be served to you by Dependency Injection, or it would be listening to a Messenger of some sort. Here’s the core class definition:

internal class SoundPlayer : BindableBase
{
    private static SoundPlayer instance = new SoundPlayer();
    private static MediaElement ForegroundPlayer { get; set; }
    private static MediaElement BackgroundPlayer { get; set; }

    public static SoundPlayer Instance
    {
        get
        {
            return instance;
        }
    }

    public bool IsBackgroundMuted
    {
        get
        {
            if (BackgroundPlayer == null)
            {
                return false;
            }

            return BackgroundPlayer.IsMuted;
        }

        set
        {
            if (BackgroundPlayer != null)
            {
                BackgroundPlayer.IsMuted = value;
                this.OnPropertyChanged("IsBackgroundMuted");
            }
        }
    }

    public async Task Play(Sounds sound, bool inBackground = false)
    {
        var mediaElement = inBackground ? BackgroundPlayer : ForegroundPlayer;

        if (mediaElement == null)
        {
            return;
        }

        string source = string.Format("ms-appx:///Assets/{0}.mp3", sound.ToString());
        mediaElement.Source = new Uri(source);

        await mediaElement.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
        {
            mediaElement.Stop();
            mediaElement.Play();
        });
    }
}

The Play method was made asynchronous to keep the UI responsive. The list of available sound effects is contained in an enumeration that maps the physical mp3 assets that you can see in the previous screen shot. That makes it easy for all components to select the sound effect they want to play:

public enum Sounds
{
    Nature,
    Sweep,
    Bell
}

By the way, if you’re looking for royalty-free sound effects, you may want to check SoundGator or SoundBible.

The SoundPlayer is now accessible from the View components. So you could decide to start some background music after a page is loaded:

protected async override void OnLoaded(object sender, RoutedEventArgs e)
{
    base.OnLoaded(sender, e);
    await SoundPlayer.Instance.Play(Sounds.Nature, true);
}

The SoundPlayer is also accessible from the (View)Model components. Here's the code for the Bell command in the MainViewModel:

private async void Bell_Executed()
{
    await SoundPlayer.Instance.Play(Sounds.Bell);
}

None of these app components are actually aware of the MediaElement instances that are doing the work. That knowledge is encapsulated in the custom Frame style and the SoundPlayer itself.

Here’s the full source code, it was written with Visual Studio 2013 Update 2. Feel free to adapt it to your favorite MVVM framework: U2UC.WinUni.Sound.zip (1.3MB)

Enjoy!

XAML Brewer

Universal App with Lex.DB

This article shows how to create a Universal Windows App that stores its local data in Lex.DB. This is a lightweight, developer-friendly in-process database engine, completely written in C#. For an introduction to building Store Apps on top of Lex.DB, please check this article of mine. For a more advanced dive into performance tuning, check this one – and make sure you don’t skip the valuable comments from Lex Lavnikov, the author of Lex.DB, at the end.

Lex.DB can be used on .NET 4+, Silverlight 5+, Windows Phone 8+, WinRT 8+, and Xamarin. Recently this alternative for SQLite was upgraded to support Universal Windows Apps.

I created a straightforward sample app, based on the Universal App with SQLite blog post by Nicolò Carandini. I added a tiny MVVM Framework with BindableBase and RelayCommand just for fun. The sample app manages a list of Person instances.

This is the Person class, as simple as can be:

public class Person
{
    public int Id { get; set; }

    public string Name { get; set; }

    public string Degree { get; set; }

    public string Occupation { get; set; }
}

The sample app comes with commands to add a Person, delete the selected Person, and reset the database to its default content. Here’s how it looks like in the emulator and the simulator:

EmulatorAndSimulator

You just need to add the Lex.DB Nuget package in your solution:

LexdbNuget

Each of the platform-specific projects will reference its own Lex.DB dll. That’s a lot simpler than SQLite, where you need to install an SDK, reference the C++ runtime *and* integrate some extra source code into your projects. The following screenshots illustrate the impact of both databases to your Visual Studio solution, with SQLite on the left, and Lex.DB on the right:

ProjectReferences

Here’s how the data access layer creates a reference to the database – in a static constructor:

private static DbInstance db;

static Dal()
{
    // Create database
    db = new DbInstance("Storage", ApplicationData.Current.RoamingFolder);

    // Define table mapping
    // * 1st parameter is primary key
    // * 2nd parameter is autoGen e.g. auto-increment
    db.Map<Person>().Automap(p => p.Id, true);

    // Initialize database
    db.Initialize();
}

The following method returns the content of the Person table:

public static IEnumerable<Person> GetPeople()
{
    return db.Table<Person>();
}

I defined two methods to insert/update Person instances: one for a single instance (it returns the generated primary key) and another one to save a list (in one transaction – read the already mentioned perfomance tuning article for more details):

public static int SavePerson(Person person)
{
    db.Table<Person>().Save(person);
    return person.Id;
}

public static Task SavePeople(IEnumerable<Person> people)
{
    return db.Table<Person>().SaveAsync(people);
}

Here’s how to give your database some initial (default) content:

public static Task ResetPeople()
{
    // Clear
    db.Purge<Person>();

    // Repopulate
    return Dal.SavePeople(
        new List<Person>()
        {
            new Person() { Name="Leonard Leakey Hofstadter", Degree="Ph.D.", Occupation="Experimental physicist"},
            new Person() {Name="Sheldon Lee Cooper", Degree="Ph.D.", Occupation="Theoretical physicist"},
            new Person() {Name="Howard Joel Wolowitz", Degree="M.Eng.", Occupation="Aerospace engineer"},
            new Person() {Name="Rajesh Ramayan Koothrappali", Degree="Ph.D.", Occupation="Astrophysicist"}
        });
}

For the sake of completeness, here’s the delete method:

public static Task DeletePeople(IEnumerable<Person> people)
{
    return db.Table<Person>().DeleteAsync(people);
}

Here’s the full source code of the sample app, it was written in Visual Studio 2013 Update 2: U2UC.WinUni.LexDBSample.zip (1.2MB)

Enjoy!

XAML Brewer

A Marching Ants Animation for Universal Windows Apps

ants-line In a lot of apps we need to draw lines on some kind of map to display a route. If you want such line to also indicate the driving direction and speed, then you could apply the Marching Ants Effect, where you represent the route as a dotted or dashed line and let the dashes walk slowly sideways and up and down. In the XAML world, this is remarkably easy. All you need to do is apply a dash pattern to the line (or PolyLine, or any other Shape) through the Shape.StrokeDashArray property and then animate its Shape.StrokeDashOffset. Here’s an example of the effect – since a screenshot would be rather silly, I created a movie where you see the marching ants (well, in this case they might be orcs) in the attached sample project: MarchingAnts.wmv (1.4MB)

As mentioned, you have to first make the line look as an ants line, so use the appropriate values for the Shape.StrokeDashCap and Shape.StrokeLineJoin properties:

Polyline line = new Polyline();

// Add Points
// line.Points.Add(new Point(...));

line.Stroke = new SolidColorBrush(Colors.OrangeRed);
line.StrokeThickness = 18;
line.StrokeDashArray = new DoubleCollection() { 4, 2 };
line.StrokeDashCap = PenLineCap.Round;
line.StrokeLineJoin = PenLineJoin.Round;

For the animation I use a Storyboard with nothing but a DoubleAnimation on the Shape.StrokeDashOffset property. That offset moves from 0 to the total length of the dash pattern, which can be conveniently calculated with a LINQ Sum operator. I implemented it as an extension method to the Shape class. It only takes the duration of the animation as a parameter:

public static void ApplyMarchingAntsAnimation(this Shape shape, TimeSpan duration)
{
    Storyboard storyboard = new Storyboard();
    DoubleAnimation doubleAnimation = new DoubleAnimation();
    doubleAnimation.From = 0.0;
    doubleAnimation.To = -shape.StrokeDashArray.Sum();
    doubleAnimation.Duration = new Duration(duration);
    doubleAnimation.AutoReverse = false;
    doubleAnimation.RepeatBehavior = RepeatBehavior.Forever;
    doubleAnimation.EnableDependentAnimation = true; // Don't forget
    storyboard.Children.Add(doubleAnimation);
    Storyboard.SetTarget(doubleAnimation, shape);
    Storyboard.SetTargetProperty(doubleAnimation, "StrokeDashOffset");
    storyboard.Begin();
}

You can apply the animation to the Stroke of any Shape with the following one-liner:

line.ApplyMarchingAntsAnimation(TimeSpan.FromSeconds(1));

Everything is implemented in the shared part of a universal app, so it works on the desktop, the tablet and the phone too. This is just a screenshot, but I assure you “it’s alive…”:

MarchingAntsScreens

Here’s the whole source, it was written in Visual Studio 2013 Update 2: U2UC.WinUni.MarchingAnts.zip (555.9KB)

Enjoy!

XAML Brewer

A Show-All-Or-Nothing Behavior for Windows Universal Apps

Universal apps need to have a responsive UI that adapts to hugely differing form factors. This article describes how to build a Border control that hides its content when it’s too large to be fully displayed on the screen. It is implemented as a behavior, since –unlike in WPF- all native WinRT and Windows Phone controls are sealed. Originally, I had built a HideOnTrimTextBlock: a TextBlock that displays nothing if the text becomes too wide to display. The calculation was triggered when the TextBlock’s size changed. I soon discovered two things:

  • the SizeChanged event for a TextBlock is often swallowed by its parent, so you have to walk up the visual tree to hook event handlers there, and
  • the code used only members of FrameworkElement, so it was applicable to more than just TextBlock controls.

So I turned the HideOnTrimTextBlock into a ShowAllOrNothingBorder.

To detect whether the content of an element is too wide to be displayed, we compare its DesiredSize (don’t forget to Measure first) with its rendered ActualWidth.

I implemented this test as an extension method:

public static class FrameworkElementExtensions
{
    /// <summary>
    /// Returns whether or not the content of the element is too wide to be displayed entirely.
    /// </summary>
    public static bool IsContentTooWide(this FrameworkElement element)
    {
        element.Measure(new Size(double.MaxValue, double.MaxValue));
        return element.DesiredSize.Width > (element.ActualWidth + 1);
    }
}

I only check the Width here, feel free to bring the Height into the equation.

The ShowAllOrNothing Universal Behavior implements IBehavior and applies to any Border. In the SizeChanged we verify whether the content is too wide or not, and adjust the Opacity of the border's Child (alternatively you could play on the Visibility). Here’s the whole behavior:

/// <summary>
/// A behavior that makes a Border's content disappear when it doesn't entirely fit the screen.
/// </summary>
public class ShowAllOrNothingBehavior : DependencyObject, IBehavior
{
    private Border border;

    public DependencyObject AssociatedObject
    {
        get { return this.border; }
    }

    public void Attach(DependencyObject associatedObject)
    {
        if (associatedObject is Border)
        {
            this.border = associatedObject as Border;
            this.border.SizeChanged += this.Border_SizeChanged;
        }
        else
        {
            throw new Exception("ShowAllOrNothingBehavior Behavior only applies to Border.");
        };
    }

    private void Border_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        if (this.border.IsContentTooWide())
        {
            this.border.Child.Opacity = 0;
        }
        else
        {
            this.border.Child.Opacity = 1;
        }
    }

    public void Detach()
    {
        if (this.border != null)
        {
            this.border.SizeChanged -= this.Border_SizeChanged;
        }
    }
}

Here’s how to attach the behavior in XAML:

<Page ...
      xmlns:interactivity="using:Microsoft.Xaml.Interactivity"
      xmlns:behaviors="using:U2UC.WinUni.Behaviors"
      ...>

<Border>
    <interactivity:Interaction.Behaviors>
        <behaviors:ShowAllOrNothingBehavior />
    </interactivity:Interaction.Behaviors>
    <TextBlock Text="I'm sorry, Dave. I'm afraid I can't do that." />
</Border>

Here’s a screen shot of the attached sample app. It illustrates a number of text block responsiveness options, such as word wrapping, character trimming, word trimming, and shrinking. The ShowAllOrNothing behavior is attached to the last one:

app_1

The slider at the bottom of the screen determines the width of the text blocks’ parent. When you slide it to the left you’ll see the last text immediately disappear when it’s touched by the red line:

app_2

In some use cases it makes sense to entirely hide a control if it doesn’t fit the screen. In the following screen shot, I believe that none of the text blocks actually produce any useful output:

app_3

Since it’s a Universal app, it’s also supposed to work on the phone:

phone_1 phone_2

All the code is sitting in the Shared project of a Universal App solution. The Windows 8.1 and Windows Phone 8.1 apps just need to reference their own platform-specific Behaviors SDK:

UniversalBehaviorSolution

You may want to implement this behavior in a Portable Class Library instead. In that case I suggest you first read this article by Joost van Schaik.

For the sake of completeness, here’s how this code would look like in WPF. Since the control classes are not sealed, we can put everything in a Border subclass:

// Wpf Control.
namespace WpfApplication
{
    using System.Windows;
    using System.Windows.Controls;

    /// <summary>
    /// A Border that makes its content disappear when it doesn't entirely fit the screen.
    /// </summary>
    public class ShowAllOrNothingBorder : Border
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="ShowAllOrNothingBorder"/> class.
        /// </summary>
        public ShowAllOrNothingBorder()
        {
            this.SizeChanged += ShowAllOrNothingBorder_SizeChanged;
        }

        /// <summary>
        /// Determines whether content is too wide.
        /// </summary>
        public bool IsContentTooWide()
        {
            this.Measure(new Size(double.MaxValue, double.MaxValue));
            return this.DesiredSize.Width > (this.ActualWidth + 1);
        }

        private void ShowAllOrNothingBorder_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (IsContentTooWide())
            {
                this.Child.Opacity = 0;
            }
            else
            {
                this.Child.Opacity = 1;
            }
        }
    }
}

Here’s the full source code, it was written in Visual Studio 2013 Update 2: U2UC.WinUni.Behavior.zip (132.2KB)

Enjoy!

XAML Brewer

Tracking with Tiles and Toasts

This article shows a way to implement multiple alarm clock functionality in a Windows (Store or Enterprise) MVVM XAML App. We’ll use locally scheduled Toast and Tile Notifications to track the progress of a workflow - like a workout scheme or a cooking recipe. The workflow can be started, paused, restarted, and canceled by the user. The app will schedule, reschedule, and unschedule the appropriate Toast and Tile Notifications so that the process can be monitored by the end user on the machine, even when the app gets suspended. Here’s a screenshot of the sample app, it monitors a classic cooking recipe:

Start

When the app is started for the first time, it creates the workflow steps, and welcomes you with a regular toast. I use a helper class that can spawn three different toasts. These toasts are a replacement for the classic Info, Warning, and Error message boxes. Here’s the whole class, I already use it in several published Store apps:

    /// <summary>
    /// Issues Toast Notifications.
    /// </summary>
    public static class Toast
    {
        /// <summary>
        /// Shows the specified text in a toast.
        /// </summary>
        public static void Show(string title, string text)
        {
            Toast.Show(title, text, null);
        }

        /// <summary>
        /// Shows a toast with an info icon.
        /// </summary>
        public static void ShowInfo(string title, string text)
        {
            Toast.Show(title, text, "ms-appx:///Assets/Toasts/Wink.png");
        }

        /// <summary>
        /// Shows a toast with a warning icon.
        /// </summary>
        public static void ShowWarning(string title, string text)
        {
            Toast.Show(title, text, "ms-appx:///Assets/Toasts/Worried.png");
        }

        /// <summary>
        /// Shows a toast with an error icon.
        /// </summary>
        public static void ShowError(string title, string content)
        {
            Toast.Show(title, content, "ms-appx:///Assets/Toasts/Confused.png");
        }

        /// <summary>
        /// Shows a toast with the specified text and icon.
        /// </summary>
        private static void Show(string title, string content, string imagePath)
        {
            XmlDocument toastXml = GetToast(title, content, imagePath);

            ToastNotification toast = new ToastNotification(toastXml);
            ToastNotificationManager.CreateToastNotifier().Show(toast);
        }

        /// <summary>
        /// Gets the toast.
        /// </summary>
        private static XmlDocument GetToast(string title, string content, string imagePath)
        {
            string toastXmlString =
                "<toast>\n" +
                    "<visual>\n" +
                        "<binding template=\"ToastImageAndText02\">\n" +
                            "<image id=\"1\" src=\"" + imagePath + "\"/>\n" +
                            "<text id=\"1\">" + title + "</text>\n" +
                            "<text id=\"2\">" + content + "</text>\n" +
                        "</binding>\n" +
                    "</visual>\n" +
                "</toast>\n";

            XmlDocument toastXml = new XmlDocument();
            toastXml.LoadXml(toastXmlString);

            return toastXml;
        }
    }

Here’s the welcome toast call:

Toast.ShowInfo("Welcome", "I created some default alarms for you.");

And this is how the result looks like:

ToastAtStart

Toast Notifications can be displayed immediately, but they can also be scheduled for the future. Let’s take a look at that, and dive into some other helper classes.

Each step in the chicken recipe workflow is represented by an instance of the Alarm class – the ViewModel to a Toast Notification. An alarm is in one of these states:

    /// <summary>
    /// Alarm States.
    /// </summary>
    public enum AlarmStates
    {
        New,
        Scheduled,
        Paused,
        Canceled,
        Delivered
    }

The Alarm helper class comes with expected properties such as an Identifier, Title, Content, State, and TimeSpan. The TimeLeft is a calculated property:

        /// <summary>
        /// Gets the time left.
        /// </summary>
        public TimeSpan TimeLeft
        {
            get
            {
                switch (this.State)
                {
                    case AlarmStates.New:
                        return this.timeSpan;
                    case AlarmStates.Scheduled:
                        return this.timeSpan.Add(this.enabledAt - DateTime.Now);
                    case AlarmStates.Paused:
                        return this.timeSpan;
                    case AlarmStates.Canceled:
                        return TimeSpan.FromSeconds(0);
                    case AlarmStates.Delivered:
                        return TimeSpan.FromSeconds(0);
                    default:
                        return TimeSpan.FromSeconds(0);
                }
            }
        }

Each Alarm is scheduled when the workflow starts, and has to notify the user when its associated step starts. Here’s the code that schedules an alarm; we update its state and schedule a Toast Notification:

        /// <summary>
        /// Schedules this instance.
        /// </summary>
        public async Task Schedule()
        {
            if (this.state == AlarmStates.Scheduled || this.state == AlarmStates.Delivered)
            {
                // No action.
                return;
            }

            if (this.state == AlarmStates.Paused)
            {
                this.TimeSpan = this.TimeLeft;
            }

            this.enabledAt = DateTime.Now;
            this.ScheduleToast();
            this.State = AlarmStates.Scheduled;

            await RemovePersistedAlarm(this);
        }

The Toast Notification is scheduled through a ToastNotifier that registers a ScheduledToastNotification by calling AddToSchedule. For a introduction to all of these, check the alarm toast notifications sample on MSDN, which also demonstrates Snoozing and Dismiss functionality. Here’s the scheduling source code:

        /// <summary>
        /// The toast notifier
        /// </summary>
        private static ToastNotifier toastNotifier = ToastNotificationManager.CreateToastNotifier();

        /// <summary>
        /// Schedules the toast.
        /// </summary>
        private void ScheduleToast()
        {
            if (this.TimeSpan <= TimeSpan.FromSeconds(0))
            {
                return;
            }

            XmlDocument toastXml = GetToast();
            var toast = new ScheduledToastNotification(toastXml, DateTime.Now.Add(this.TimeSpan));
            toast.Id = this.Id;
            toastNotifier.AddToSchedule(toast);
        }

        /// <summary>
        /// Gets the toast.
        /// </summary>
        private XmlDocument GetToast()
        {
            string toastXmlString =
                "<toast duration=\"long\">\n" +
                    "<visual>\n" +
                        "<binding template=\"ToastImageAndText02\">\n" +
                            "<image id=\"1\" src=\"ms-appx:///Assets/Toasts/AlarmClock.png\"/>\n" +
                            "<text id=\"1\">" + this.title + "</text>\n" +
                            "<text id=\"2\">" + this.content + "</text>\n" +
                        "</binding>\n" +
                    "</visual>\n" +
                    "<audio src=\"ms-winsoundevent:Notification.Looping.Alarm2\" loop=\"true\" />\n" +
                "</toast>\n";

            XmlDocument toastXml = new XmlDocument();
            toastXml.LoadXml(toastXmlString);

            return toastXml;
        }

If you don’t like working with the raw XML version of the toast content, then I suggest you take a look at the NotificationsExtensions project. That project contains a more developer friendly wrapper around all of this.

A scheduled toast notification appears (and sounds) right on time, whether the app is active or not:

BasketToast

ToastNoApp

By the way: scheduled toast notifications –as well as scheduled tile notifications, see further- nicely survive restarts of your machine.

Back to the sample app. The entire workflow as such is not remembered. When the user stops and restarts the app, we recreate the list of alarms based on the scheduled toasts – that’s what GetScheduledToastNotifications does:

        /// <summary>
        /// Returns the scheduled alarms.
        /// </summary>
        public static IEnumerable<Alarm> ScheduledAlarms()
        {
            var toasts = toastNotifier.GetScheduledToastNotifications();

            return from t in toasts
                   select (Alarm)t;
        }

All we have to do is convert each native ScheduledToastNotification back to an instance of our Alarm ViewModel class. I used a conversion operator for that. If you’re dealing with the raw XML representation for the toasts, then you need to apply some XPATH magic (in SelectSingleNode) to get some of the data back:

        /// <summary>
        /// Performs an implicit conversion from <see cref="ScheduledToastNotification"/> to <see cref="Alarm"/>.
        /// </summary>
        public static implicit operator Alarm(ScheduledToastNotification toast)
        {
            Alarm result = new Alarm();

            result.Id = toast.Id;
            result.TimeSpan = toast.DeliveryTime - DateTime.Now;
            result.enabledAt = DateTime.Now;
            result.State = AlarmStates.Scheduled;

            var node = toast.Content.SelectSingleNode("//text[@id=1]");
            if (node != null)
            {
                result.Title = node.InnerText;
            }

            node = toast.Content.SelectSingleNode("//text[@id=2]");
            if (node != null)
            {
                result.Content = node.InnerText;
            }

            return result;
        }

The sample app allows an alarm to be paused, which is something that a native scheduled toast notification can’t handle. When an alarm is paused, we upgrade its state and remove the corresponding toast notification from the schedule:

        /// <summary>
        /// Pauses this instance.
        /// </summary>
        public async Task Pause()
        {
            if (this.state != AlarmStates.Scheduled)
            {
                // No action.
                return;
            }

            this.TimeSpan = this.TimeLeft;
            this.State = AlarmStates.Paused;
            this.UnscheduleToast();

            await AddPersistedAlarm(this);
        }

For unscheduling the toast, we look it up by its identifier through a LINQ query against GetScheduledToastNotifications, and remove it from the list with RemoveFromSchedule:

        /// <summary>
        /// Unschedules the toast.
        /// </summary>
        private void UnscheduleToast()
        {
            var toasts = toastNotifier.GetScheduledToastNotifications();
            var found = (from t in toasts
                         where t.Id == this.Id
                         select t).FirstOrDefault();
            if (found != null)
            {
                toastNotifier.RemoveFromSchedule(found);
            }
        }

For a paused alarm there’s no corresponding ScheduledToastNotification anymore, so when the app is suspended, it would be lost. To prevent this, we serialize the paused alarms as a list in the local folder so we can deserialize it when the app restarts. Here’s the corresponding code for all of this:

        /// <summary>
        /// The serializer
        /// </summary>
        private static AbstractSerializationBase<List<Alarm>> serializer =
            new XmlSerialization<List<Alarm>>()
            {
                FileName = "Alarms.xml",
                Folder = ApplicationData.Current.LocalFolder
            };

        /// <summary>
        /// Returns the persisted alarms.
        /// </summary>
        public static async Task<List<Alarm>> PersistedAlarms()
        {
            return await serializer.Deserialize();
        }

        /// <summary>
        /// Adds a persisted alarm.
        /// </summary>
        private static async Task AddPersistedAlarm(Alarm alarm)
        {
            var alarms = await PersistedAlarms();

            await RemovePersistedAlarm(alarm);

            alarm.TimeSpan = alarm.TimeLeft;
            alarms.Add(alarm);

            await serializer.Serialize(alarms);
        }

I reused the XML Serializer from this article. Because the native XML Serializer doesn’t handle the TimeSpan data type very well, I applied a little trick to serialize and deserialize the TimeSpan property. I created (serializable) shadow property that holds the number of Ticks in it:

        /// <summary>
        /// Gets or sets the time span.
        /// </summary>
        /// <remarks>Not XML serializable.</remarks>
        [XmlIgnore]
        public TimeSpan TimeSpan
        {
            get { return this.timeSpan; }
            set { this.SetProperty(ref this.timeSpan, value); }
        }

        /// <summary>
        /// Gets or sets the time span ticks.
        /// </summary>
        /// <remarks>Pretended property for serialization</remarks>
        [XmlElement("TimeSpan")]
        public long TimeSpanTicks
        {
            get { return this.timeSpan.Ticks; }
            set { this.timeSpan = new TimeSpan(value); }
        }

When an individual alarm is disabled, then we unschedule the corresponding toast notification, and remove it from the list of persisted alarms:

        /// <summary>
        /// Disables this instance.
        /// </summary>
        public async Task Disable()
        {
            if (this.state != AlarmStates.Scheduled && this.state != AlarmStates.Paused)
            {
                // No action.
                return;
            }

            this.UnscheduleToast();
            this.State = AlarmStates.Canceled;

            await RemovePersistedAlarm(this);
        }
        /// <summary>
        /// Unschedules the toast.
        /// </summary>
        private void UnscheduleToast()
        {
            var toasts = toastNotifier.GetScheduledToastNotifications();
            var found = (from t in toasts
                         where t.Id == this.Id
                         select t).FirstOrDefault();
            if (found != null)
            {
                toastNotifier.RemoveFromSchedule(found);
            }
        }
        /// <summary>
        /// Removes a persisted alarm.
        /// </summary>
        private static async Task RemovePersistedAlarm(Alarm alarm)
        {
            var alarms = await PersistedAlarms();

            alarms.RemoveAll(a => a.Id == alarm.Id);

            await serializer.Serialize(alarms);
        }

When the user starts the app by tapping on the tile, or on a toast, the app reassembles the (remaining) workflow by combining the scheduled toast notifications with the serialized paused alarms (we deliberately forget the steps for which the alarms were delivered). So this is how the app looks like after a restart:

Reopen

This is the code that brings back the list of alarms, it comes from the constructor of the main view model – which actually represents the workflow:

            // Create an alarm for all scheduled notifications from previous sessions that are still running.
            var scheduled = Alarm.ScheduledAlarms();

            if (scheduled.Count() > 0)
            {
                foreach (var alarm in scheduled)
                {
                    this.alarms.Add(alarm);
                }
            }

            CoreWindow.GetForCurrentThread().Dispatcher.RunAsync
                (
                    CoreDispatcherPriority.Normal,
                    async () =>
                    {
                        // Rehydrate paused alarms.
                        var persisted = await Alarm.PersistedAlarms();
                        if (persisted.Count() > 0)
                        {
                            foreach (var alarm in persisted)
                            {
                                this.alarms.Add(alarm);
                            }
                        }

                        // Create default alarms.
                        if (this.alarms.Count == 0)
                        {
                            Toast.ShowInfo("Welcome", "I created some default alarms for you.");
                            this.CreateDefaultAlarms();
                        }

                        this.RescheduleTiles();
                    }
                );

            DispatcherTimer toastTimer = new DispatcherTimer();
            toastTimer.Tick += this.ToastTimer_Tick;
            toastTimer.Interval = TimeSpan.FromSeconds(1);
            toastTimer.Start();

At the end of the previous code snippet, you see that we fire up a timer with a short interval (1 second). This timer updates the UI so the user has a detailed view on the workflow status through the changing TimeLeft fields. But it doesn’t stop here: we also want to give the user a high level –but less accurate- overview of the status of the running workflow. Therefor we decorate the app’s live tile with a message that contains the remaining time to the next notification and the remaining time for the entire flow. For that we schedule a regular tile update; every minute for the sample app, but I can imagine you would want a larger interval for a production app. Here’s the code to schedule these tile notifications, it’s very similar to the toast scheduling. This code is executed when the app restarts, when user modifies the flow, and also on a slow(er) moving timer.

For each minute between the current moment and the end of the workflow we lookup the next upcoming toast, and create the corresponding title and message on the live tile. The sample app notifies only the TimeLeft values, but you have access to all properties of the associated alarms (including Title and Content) if you want. Just remember that you only have three short lines of text for the tile:

        /// <summary>
        /// Reschedules the tiles.
        /// </summary>
        private void RescheduleTiles()
        {
            var scheduledAlarms = this.ScheduledAlarms;

            var nextAlarm = scheduledAlarms.FirstOrDefault();
            var lastAlarm = scheduledAlarms.LastOrDefault();

            if (nextAlarm == null)
            {
                // No alarms
                UnscheduleTileNotifications();
                return;
            }

            var next = (DateTime.Now + nextAlarm.TimeLeft) - nextAlarmTime;
            var nextMinutes = next.TotalMinutes;

            var last = (DateTime.Now + lastAlarm.TimeLeft) - lastAlarmTime;
            var lastMinutes = last.TotalMinutes;

            if ((Math.Abs(nextMinutes) < 2) && Math.Abs(lastMinutes) < 2)
            {
                // Nothing changed since the previous check.
                return;
            }

            nextAlarmTime = DateTime.Now.Add(nextAlarm.TimeLeft);
            lastAlarmTime = DateTime.Now.Add(lastAlarm.TimeLeft);

            UnscheduleTileNotifications();

            DateTime dateTime = DateTime.Now.AddSeconds(5);
            while (dateTime < lastAlarmTime)
            {
                string title = "Cooking";

                var alarm = (from a in scheduledAlarms
                             where a.TimeLeft > dateTime - DateTime.Now
                             select a).FirstOrDefault();

                if (alarm != null)
                {
                    string content;

                    if (alarm != lastAlarm)
                    {
                        content = String.Format(
                             "Notifies in {0} min.\nEnds in {1} min.",
                             (alarm.TimeLeft - (dateTime - DateTime.Now)).Minutes + 1,
                             (lastAlarm.TimeLeft - (dateTime - DateTime.Now)).Minutes + 1);
                    }
                    else
                    {
                        content = String.Format(
                             "Ends in {0} min.",
                             (lastAlarm.TimeLeft - (dateTime - DateTime.Now)).Minutes + 1);
                    }

                    tileUpdater.AddToSchedule(new ScheduledTileNotification(this.GetTile(title, content), dateTime));
                    Debug.WriteLine("Scheduled Tile Notification for {0}.", dateTime);
                }

                dateTime = dateTime.Add(TimeSpan.FromMinutes(1));
            }

            // Done.
            tileUpdater.AddToSchedule(new ScheduledTileNotification(this.GetTile("Job done", string.Empty), dateTime));
        }

Here’s an MS-Paintoshopped image of the evolution of the sample app's live tile throughout the workflow:

TileEvolution

The ‘Job Done’ tile notification is the last one. The tile remains like this until the app is restarted, since there seems to be no way to bring back the default tile, at least not through the scheduling infrastructure. If you really need this functionality, you could start a background job. Anyway, here’s the call to bring back the default tile:

//Reset to default tile.
tileUpdater.Clear();

The sample app uses a strictly sequential workflow, but the Alarm ViewModel class is reusable in more complex scenario’s with e.g. parallel tasks or tasks that can be paused individually.

Here’s the full source code, it was built with Visual Studio 2013 Update 2: U2UC.Win8.Alarms.zip (314.3KB)

Enjoy!

Diederik

Building Enterprise Side-loaded apps with OWIN

This article shows how a side-loaded line-of-business Windows app can communicate through HTTP with a locally installed desktop component (a .NET class library) by making use of the Open Web Interface for .NET. Apps that are loaded from the Store can still not leave the sandbox and can only connect to servers, but since Windows 8.1 side-loaded Enterprise apps are allowed to open ports in the firewall around their own app container. Such apps are now allowed e.g. to connect to http://localhost. For more info, just check the first half of this Build 2014 session.

I can imagine that a lot of companies would like to roll out some Modern LOB apps that talk to locally installed components. HTTP is a nice protocol for that, and ASP.NET Web API would make a nice host to expose local components. If that’s your idea too, then here’s the bad news: most network administrators will simply not allow the installation/activation of an infrastructure such as IIS on the regular workstation of each employee. But don’t worry, here’s the good news: among a lot of other capabilities, the Open Web Interface for .NET (OWIN) allows you to self-host a lightweight web server in a Windows service or a console application without the need for IIS.

To illustrate this configuration, I built a small app that talks to a localhost REST provider in a .NET console app which in its turn accesses a local “legacy” .NET class library. Here’s how the app looks like:

AppWithOwin

The resemblance of this app with the one from my previous blog post is not a coincidence, of course; and I’m also reusing the legacy projects. I just added an extra button to the Windows Forms application to test the new OWIN call:

FormsClient

This particular use of OWIN has the same purpose as Brokered Windows Runtime Components: connecting Modern touch-optimized apps to software components local to the desktop.

Here we go, let’s start with a self-hosted Web API server. In a production environment we would do this in a Windows Service, but for now just create a new C# Windows console, no special template needed:

ConsoleApp

It may add too many references, but the fastest way to take off with OWIN as a Web API host, is installing the ASP.NET Web API OWIN Self Host Nuget package:

OwinNuget

Create a StartUp class to configure the host. If you ever encountered ASP.NET MVC or Web API, then it should look familiar:

namespace U2UC.WinLob.OwinHost
{
    using Owin;
    using System.Web.Http;

    public class Startup
    {
        // This code configures Web API. The Startup class is specified as a type
        // parameter in the WebApp.Start method.
        public void Configuration(IAppBuilder appBuilder)
        {
            // Configure Web API for self-host. 
            HttpConfiguration config = new HttpConfiguration();
            config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "api/{controller}/{id}",
                defaults: new { id = RouteParameter.Optional }
            );

            appBuilder.UseWebApi(config);
        }
    }
}

Then add a Web API controller that wraps the legacy component (add a reference) in a REST interface. The sample app will only use a GET call to retrieve the list of Northwind employees (as a JSON array):

namespace U2UC.WinLob.OwinHost
{
    using System;
    using System.Collections.Generic;
    using System.Web.Http;

    public class NorthwindController : ApiController
    {
        public IEnumerable<Employee> Get()
        {
            List<Employee> result = new List<Employee>();

            foreach (var emp in U2UC.WinLob.Legacy.Dal.GetAllEmployees())
            {
                result.Add(
                    new Employee() 
                        {
                            Name = emp.Name,
                            Title = emp.Title,
                            BirthDate = emp.BirthDate,
                            Picture = Convert.ToBase64String(emp.Picture)
                        }
                    );
            }

            return result;
        }
    }
}

The last step is to start up the OWIN host, that’s done in the console’s Main routine. The test call is not really necessary, but it’s there to show us that the host is operational:

namespace U2UC.WinLob.OwinHost
{
    using Microsoft.Owin.Hosting;
    using Newtonsoft.Json;
    using System;
    using System.Collections.Generic;
    using System.Net.Http;

    // More details on hosting WebApi here:
    // http://www.asp.net/web-api/overview/hosting-aspnet-web-api/use-owin-to-self-host-web-api
    public class Program
    {
        static void Main()
        {
            string baseAddress = "http://localhost:9000/";

            // Start OWIN host 
            using (WebApp.Start<Startup>(url: baseAddress))
            {
                // Create HttpCient and make a request to api/northwind 
                HttpClient client = new HttpClient();
                var response = client.GetStringAsync(baseAddress + "api/northwind").Result;

                List<Employee> employees = JsonConvert.DeserializeObject<List<Employee>>(response);

                Console.WriteLine("{0} Northwind employees found.", employees.Count);

                Console.ReadLine(); // In the using, not after it like in the demo :-)
            }
        }
    }
}

When the console app is started, it looks like this:

TestHost

The console app is now exposing the functionality of the legacy library through HTTP, REST, and JSON.

Let’s take a look at the side-loaded Modern app now. It helps to make a reference to JSON.NET:

JsonApp

When the app needs to call the legacy code, it creates a HttpClient, executes the asynchronous call, and parses the JSON result. By the way: JSON.NET comes with excellent LINQ capabilities for that last step. The following code snippet comes from the code-behind of the page. I'm not using MVVM here, shame on me:

private void AppBarButton_Click(object sender, RoutedEventArgs e)
{
    // Create HttpCient and make a request to api/northwind 
    var client = new HttpClient();
    var json = client.GetStringAsync(new Uri("http://localhost:9000/api/northwind")).Result;
            
    var employees = JsonConvert.DeserializeObject<List<Employee>>(json);

    this.Employees.ItemsSource = employees;
}

That’s it: the app now accesses local legacy code using only standard protocols. I’m missing something in the varbinary-bytearray-base64string-bitmapimage conversion of the database pictures, but it’s still a representative demo :-)

Here’s the full sample app, it was built with Visual Studio 2013. Just remember to define the App and the OwinHost as startup projects : U2UC.WinLob.Owin.zip (8MB)

Enjoy!

XAML Brewer

Building Enterprise apps using Brokered Windows Runtime Components

This article shows step by step how to connect a side-loaded modern app to a legacy component via the “Brokered Windows Runtime Components for Side-Loaded applications” feature. This feature comes with Windows 8.1 Update and allows Modern apps to break outside the AppContainer and connect to desktop components such as legacy .NET class libraries. This gives the side-loaded app direct access to native platform capabilities, including COM Interop and P/Invoke. For a detailed introduction I would encourage you to take a look at this Build 2014 session by @devhawk and read this MSDN white paper. A Brokered Windows Runtime Component is a new type of component that bridges the technology gap between the Windows Runtime and the .NET world. It allows you to write a touch optimized modern Store app against legacy components that sit on the same desktop. As an example I created a legacy application with a data access layer DLL that uses SQL Server Express and Linq-to-SQL, and a Windows forms executable:

ClassicClient

Here’s the code from the data access layer that fetches the employees from the Northwind database (for the fans: the SQL script to create that database is in the source code of the attached project):

public static Dto.Employee[] GetAllEmployees()
{
    using (NorthwindDataContext northWind = new NorthwindDataContext())
    {
        var query = from e in northWind.Employees
                    select new Dto.Employee() 
                    { 
                        Name = e.FirstName + " " + e.LastName, 
                        Title = e.Title,
                        BirthDate = e.BirthDate,
                        Picture = e.Photo.ToArray()
                    };

        return query.ToArray();
    }
}

A combination of a Brokered Windows Runtime Component and a Brokered Windows ProxyStub allowed me to reuse the data access layer of that legacy application in a modern app:

ModernClient

I tried for a couple of hours to build and link the necessary components the manual way, as explained in the White Paper. But I’m not really skilled in building Runtime Components, and the last time I saw the internals of a C++ project was a very long time ago in a galaxy far away. When I was about to give up, the Brokered WinRT Component Project Templates for Visual Studio were released. And this is what happened then:

I installed the templates:

Templates

Then I added a brokered component to the solution:

AddBrokeredComponent

The Brokered Component is the component to which the side-loaded app talks. It’s a hybrid component that can get a reference to the legacy data access layer, but all its public members should be Windows Runtime compatible. This overview of Windows Runtime base data types came in handy. It’s probably obsolete in this particular sample app, but I did a bit of massaging the data. In a production application this would be the main responsibility of the Brokered Component:

public Employee[] GetAllEmployees()
{
    var dbe = Dal.GetAllEmployees();
    var result = new List<Employee>();

    foreach (var item in dbe)
    {
        result.Add(new Employee() { Name = item.Name, Title = item.Title, Age = Age(item.BirthDate) });
    }

    return result.ToArray();
}

The side-loaded app can not directly talk to the Brokered Component since it’s targeting a different framework family. The following happens when you try this out:

WrongReference

There needs to be a so called Brokered ProxySub in between the Modern app and the Brokered Windows Runtime Component. Fortunately there is a template for this:

AddBrokeredProxyStub

The ProxyStub project is preconfigured for its task and is populated by making a reference to the Brokered Runtime Component:

AddReference

Before the side-loaded app can use it, the ProxyStub needs to be registered as a COM-component. This task gets automated if you run Visual Studio as an Administrator, and configure the Linker:

AutoRegister

The Modern app needs to make a reference to the ProxyStub:

AddReference2

The side-loaded app now has access to the Brokered Component (no MVVM here since I wanted to keep this sample as straightforward as possible):

private void AppBarButton_Click(object sender, RoutedEventArgs e)
{
    var broker = new U2UC.WinLob.BrokeredComponent.RunTimeClass();
    var data = broker.GetAllEmployees();
    this.Employees.ItemsSource = data;
}

If you run the app now, it still goes wrong:

BeforeAppManifest

You have to make sure that the fully qualified name of the Brokered Component together with its path are defined in the app’s manifest:

AppManifest

Brokered Windows Runtime Components will enable the development of a new breed of corporate line-of-business apps: touch-first modern apps that are connected to existing enterprise data and processes.

Here’s the sample app, it was written with Visual Studio 2013 Update 2 (RC) for Windows 8.1 Update. If you want to play with it, don’t forget to run as Adminstrator and change the path in the app’s manifest: U2UC.WinLob.Sample.zip (1.2MB)

Enjoy!

XAML Brewer

A Radial Gauge for Universal Windows Apps

This article presents a modern radial gauge Custom Control, hosted in a Portable Class Library for Universal Windows apps. Visual Studio Update 2 comes with the concept of Universal Apps that can run on Windows PC’s, tablets, phones and the XBox. For an introduction to this new breed of apps, check this crystal clear article by Jeff Prosise. I did not develop this custom control from scratch, I just migrated my own Radial Gauge for WinRT which was designed by Arturo Toledo and is available through NuGet as part of the WinRT Xaml Toolkit. Here’s how the Universal Gauge looks like in both the emulator and the simulator:

universal

I started by creating a new solution with a blank C# Universal App. The template creates three projects:

  • a Windows Store app project,
  • a Windows Phone project, and
  • a so-called Shared project, that contains all common source files and assets.

I didn’t want to create the custom control as a bunch of shared source files, so I added an empty Portable Class Library. Visual Studio 2013 Update 2 contains a project template for such a Universal PCL:

ClassLibrary

In the class library I created a new custom control. And yes, there’s again a template for that:

CustomControl

For more information on building customs controls from scratch, you may want to read this article of mine. It seems to apply to Universal apps too.

I copied the XAML style in the Themes folder and the C# class over from the Windows Phone version of the Radial Gauge, because that’s my most recent version. I had to just (re-)adapt a couple of namespaces, and tadaa: the radial gauge custom control was operational in less than 15 minutes, with a single code base for all XAML platforms (well, almost, not sure about WPF).

While playing with the source, I added a new property -TickSpacing- as suggested by Dennis Almond in a blog post comment. Thanks, Dennis!

/// <summary>
/// Gets or sets the tick spacing, in units.
/// </summary>
public int TickSpacing
{
    get { return (int)GetValue(TickSpacingProperty); }
    set { SetValue(TickSpacingProperty, value); }
} 

The TickSpacing allows you to specify the distance between the ticks. I used to divide the scale in 10 zones, but now you can choose your own interval for the ticks. Look at the slider-bound gauge on the right: it’s divided in 5 zones:

universal2

Here’s the updated list of configurable properties:

  • Minimum: minimum value on the scale (double)
  • Maximum: maximum value on the scale (double)
  • Value: the value to represent (double)
  • ValueStringFormat: StringFormat to apply to the displayed value (string)
  • Unit: unit measure to display (string)
  • TickSpacing: spacing -in value units- between ticks (int)
  • NeedleBrush: color of the needle (Brush)
  • TickBrush: color of the outer ticks (Brush)
  • ScaleWidth: thickness of the scale in pixels – relative to the control’s default size (double)
  • ScaleBrush: background color of the scale (Brush)
  • ScaleTickBrush: color of the ticks on the scale (Brush)
  • TrailBrush: color of the trail following the needle (Brush)
  • ValueBrush: color of the value text (Brush)
  • UnitBrush: color of the unit measure text (Brush)

And the taxonomy:

taxonomy

As an example, here’s Daffy’s gauge from the sample project:

<controls:RadialGauge Value="60"
                      Unit="Quacks"
                      NeedleBrush="#FFCC2B33"
                      ScaleBrush="Transparent"
                      TrailBrush="Black"
                      TickBrush="#FFFFAA00"
                      ValueBrush="White"
                      UnitBrush="White"
                      ScaleTickBrush="DimGray" />

And here’s the data bound gauge, featuring TickSpacing:

<controls:RadialGauge Minimum="{Binding Min}"
                      Maximum="{Binding Max}"
                      Value="{Binding Value, Mode=TwoWay}"
                      TickSpacing="100"
                      Unit="Bindings"
                      NeedleBrush="White"
                      ScaleBrush="LightGray"
                      TrailBrush="OrangeRed"
                      TickBrush="LightGray"
                      ValueBrush="White"
                      UnitBrush="White"
                      ScaleTickBrush="Transparent"
                      ScaleWidth="5" />

Let’s come back to the Universal app. The Store app and the Phone app have something in common: they’re absolutely empty. It shouldn't come as a surprise that the ViewModel and the BindableBase classes are easily sharable, since they're simple C# classes. But the whole user interface is actually shared between the platform-specific apps: it's Hub-based and entirely built with common Store/Phone controls. So all the code is shared: binary through the PCL, or as source in the Shared project. Needless to say I like this approach a lot…

Here’s the full project, it was built with Visual Studio 2013 Update 2 (RC): U2UC.WinUni.CustomControlSample.zip (303.6KB)

Enjoy!

XAML Brewer

Using OneDrive files in Windows Platform Apps – Part Deux

This article presents a handful of building blocks for some more advanced OneDrive use cases in Windows 8 apps, like:

  • transparently switching between a local folder and a OneDrive working folder,
  • synchronizing a local folder with a OneDrive folder,
  • sharing a OneDrive folder across devices,
  • sharing a OneDrive folder across apps, or even
  • sharing a OneDrive folder across platforms (Store app - Phone app - side loaded Enterprise app).

It elaborates on my previous article that showed how to access a OneDrive folder from a Windows 8 Store app from a purely technical point. This code is now hardened, and refactored into a more reusable model. Although all building blocks are implemented and tested, not all of the mentioned scenarios are implemented in the attached sample app. The sample app simulates a Store app that has OneDrive capability as an option (e.g. as an in-app purchase) and that can switch back to the local folder whenever the user feels to (e.g. to work offline). This is how it looks like:

OneDrive

The sample app allows you to do some basic file operations, and comes with a manual switch to toggle between the local folder and a working folder on your OneDrive. File and folder comparison and synchronization are not elaborated, but all constituents are in the source code.

The object model contains the following classes:

  • FileSystemBase: a base class that encapsulates the basic file system operations, regardless of where the working folder lives:
    • enumerating the files in the working folder,
    • saving a file,
    • reading a file, and
    • deleting a file.
  • IFile: an interface that contains the file properties that the app is interested in:
    • name of the file,
    • size of the file (useful for synchronization),
    • modification date of the file (useful for synchronization)
  • Device: a class that represents the physical device:
    • hardware identifier, and
    • internet connectivity.

Here’s the UML class diagram of the API:

API

The FileSystemBase class abstracts the file manipulations. It’s an abstract class with concrete virtual asynchronous methods that each throw an exception. I know that looks weird, but it’s the best way to enforce child classes to implement an expected asynchronous behavior (static, abstract, interface, and async don’t really work together in a class definition):

/// <summary>
/// Base Class for File Systems.
/// </summary>
public abstract class FileSystemBase
{
    /// <summary>
    /// Returns the list of Files in the Working Folder.
    /// </summary>
    public async virtual Task<List<IFile>> Files()
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// Saves the specified content into the Working Folder.
    /// </summary>
    public async virtual Task Save(string content, string fileName)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// Returns the content of the specified file in the Working Folder.
    /// </summary>
    public async virtual Task<string> Read(string fileName)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// Deletes the specified file from the Working Folder.
    /// </summary>
    public async virtual Task Delete(string fileName)
    {
        throw new NotImplementedException();
    }
}

Both concrete child classes –LocalDrive and OneDrive- have their own implementation of the virtual methods. The OneDrive class is of course a bit more complex than the LocalDrive class, since it needs a login procedure and it requires and extra identifier for the working folder and its files. Check the sample app for the source code, I'm not repeating it in this article since it’s just a rehash of my previous blog post.

The main viewmodel of the app uses a field to refer to the file system:

private FileSystemBase currentDrive;

The app will not show command buttons as long as it’s not connected to a file system. So I added an IsReady property to the viewmodel:

/// <summary>
/// Gets a value indicating whether this instance is ready (i.e. connected to a file system).
/// </summary>
public bool IsReady
{
    get { return this.currentDrive != null; }
}

Here’s the app in its waiting mode - it may take some time to connect to OneDrive the first time:WaitUntilReady

The last used file system is stored in the roaming settings, so it can be shared between devices:

/// <summary>
/// Gets or sets a value indicating whether we're using OneDrive or Local Folder.
/// </summary>
public bool UseOneDrive
{
    get { return this.useOneDrive; }

    set
    {
        if (value != this.useOneDrive)
        {
            if (value)
            {
                this.TryEnableOneDrive();
            }
            else
            {
                this.currentDrive = LocalDrive.Current;
                this.SetProperty(ref this.useOneDrive, value);
                ApplicationData.Current.RoamingSettings.Values["UseOneDrive"] = value;
                this.OnPropertyChanged("IsReady");
            }
        }
    }
}

When the user switches to OneDrive mode, we try to activate it. In case of a problem (e.g. the user did not consent, or the drive cannot be accessed), we switch back to local mode. The OneDrive initialization code is called from strictly synchronous code - a property setter and a constructor. It executes asynchronously and finishes with property change notifications. The XAML bindings will do the rest:

private void TryEnableOneDrive()
{
    bool success = true;
    CoreWindow.GetForCurrentThread().Dispatcher.RunAsync
        (
            CoreDispatcherPriority.Normal,
            async () =>
            {
                FileSystemBase fileSystem = null;

                try
                {
                    fileSystem = await OneDrive.GetCurrent();
                }
                catch (Exception)
                {
                    success = false;
                }
                finally
                {
                    if (fileSystem == null || !OneDrive.IsLoggedIn)
                    {
                        // Something went wrong, switch to local.
                        success = false;
                        this.currentDrive = LocalDrive.Current;
                    }
                    else
                    {
                        this.currentDrive = fileSystem;
                    }

                    this.useOneDrive = success;
                    ApplicationData.Current.RoamingSettings.Values["UseOneDrive"] = success;

                    // Need to explicitly notify to reset toggle button on error.
                    this.OnPropertyChanged("UseOneDrive");
                    this.OnPropertyChanged("IsReady");
                }
            }
        );
}

Here’s how the code is called from the constructor of the viewmodel:

this.useOneDrive = (bool)ApplicationData.Current.RoamingSettings.Values["UseOneDrive"];

if (this.useOneDrive)
{
    this.TryEnableOneDrive();
}
else
{
    this.currentDrive = LocalDrive.Current;
}

In that same constructor we also check if the app has been used from another device lately, because this might trigger a synchronization routine. The use case that I have in mind here, is an app that always saves locally but uploads at regular intervals to the user’s OneDrive. Such an app would want to be informed that the OneDrive folder was updated by another device:

if (ApplicationData.Current.RoamingSettings.Values["HardwareId"] != null)
{
    string previous = (string)ApplicationData.Current.RoamingSettings.Values["HardwareId"];

    if (previous != Device.Ashwid)
    {
        this.ShowToast("You seem to have used this app from another machine!", "ms-appx:///Assets/Warning.png");
    }
}

ApplicationData.Current.RoamingSettings.Values["HardwareId"] = Device.Ashwid;

Here’s that code in action:

OtherHardware

For checking the device id, a GUID in local settings would do the job in most scenarios. But the ASHWID allows you to share the working folder between apps on the same device (you would just have to override the default working folder name for this):

/// <summary>
/// Gets the Application Specific Hardware Identifier.
/// </summary>
/// <remarks>
/// Due to hardware drift, the returned value may change over time). 
/// See http://msdn.microsoft.com/en-us/library/windows/apps/jj553431.aspx. 
/// </remarks>
public static string Ashwid
{
    get
    {
        HardwareToken hwToken = HardwareIdentification.GetPackageSpecificToken(null);
        IBuffer hwID = hwToken.Id;
        byte[] hwIDBytes = hwID.ToArray();
        return hwIDBytes.Select(b => b.ToString()).Aggregate((b, next) => b + "," + next);
    }
}

Most of the file operations are ignorant of the whereabouts of the working folder:

private async void ReadFolder_Executed()
{
    this.files.Clear();
    foreach (var file in await this.currentDrive.Files())
    {
        this.files.Add(file);
    }
}

private async void ReadFile_Executed()
{
    if (this.selectedFile != null)
    {
        this.SelectedText = await this.currentDrive.Read(this.selectedFile.Name);
    }
}

private async void DeleteFile_Executed()
{
    if (this.selectedFile != null)
    {
        var task = this.currentDrive.Delete(this.selectedFile.Name);

        try
        {
            await task;

            this.ShowToast("File deleted.");
        }
        catch (Exception ex)
        {
            this.ShowToast("There was an error while deleting.", "ms-appx:///Assets/Warning.png");
        }

        this.ReadFolderCommand.Execute(null);
    }
}

While saving a file on OneDrive you can easily pull the internet cable or disable the Wifi, so the Save method was the ideal candidate to test some extra exception handling. If something goes wrong while saving, you may want to check the connection to the Internet. Unfortunately there is no way to ask the LiveConnectClient nor the LiveConnectSession whether the connection is still available. Actually it’s even worse: you can re-login successfully without a connection, you end up with a "false positive". Fortunately you can examine your Internet connectivity in other ways:

/// <summary>
/// Gets a value indicating whether this device is currently connected to the Internet.
/// </summary>
public static bool IsConnected
{
    get
    {
        try
        {
            return NetworkInformation.GetInternetConnectionProfile().GetNetworkConnectivityLevel() >= NetworkConnectivityLevel.InternetAccess;
        }
        catch (Exception)
        {
            return false;
        }
    }
}

In a production app, it would make sense to automatically switch to local mode after a failed Save operation against OneDrive. Apparently the LiveConnectClient enters an undetectable corrupt state after an unsuccessful BackgroundUploadAsync. The next time you try to save a file –and there’s still no Internet connection- the Live client throws an exception that you can’t catch. I’m sorry I didn’t find a workaround for this yet. Anyway, the app will die on you ungracefully in this particular scenario :-(

ClientException

Here’s the whole Save method (the one in the main view model):

private async void SaveFile_Executed()
{
    if (this.selectedFile != null)
    {
        var task = this.currentDrive.Save(this.selectedText, this.selectedFile.Name);

        try
        {
            await task;

            this.ShowToast("File saved.");
        }
        catch (Exception ex)
        {
            if (this.useOneDrive && !Device.IsConnected)
            {
                this.ShowToast("Internet connection is lost. You may want to switch to local storage.", "ms-appx:///Assets/Warning.png");
            }
            else
            {
                this.ShowToast("There was an error while saving.", "ms-appx:///Assets/Warning.png");
            }
        }
    }
}

Here’s one of the toasts that notify the user of a problem:

InternetWarning

Here’s the sample app; it has the “Transparent FileSystem API” in its Models folder. The code was written in Visual Studio 2013 Update 2 RC, but I did not use any of the new Shared Project/Universal App features yet: U2UC.WinRT.OneDriveSync.zip (1.4MB)

Don’t forget to associate the project with an app of yours, or it won’t work:

AssociateStoreApp

Enjoy!

Diederik

Using OneDrive files from a Windows 8 Store app

This article explains how to let a Windows Store app manage a list of files in a working folder on the user’s OneDrive, without continuously opening file pickers. Some apps need to store more personal user data than the roaming folder can handle. A folder on the user’s OneDrive is a nice place to store that data -e.g. as flat files containing serialized business objects- and share it across his devices. Your users installed your app through the Store, so they all have a Microsoft account. And every Microsoft account comes with a OneDrive folder somewhere in the Cloud. So why not make use of it?

I made a little app that shows you how to log on to OneDrive, create a working folder for your app, upload a file, enumerate the files in the folder, and read the content of a file. Here’s how it looks like:

onedrive_commands

An HTTP client and some JSON magic would suffice to communicate with the OneDrive services directly, but the Live SDK for Windows, Windows Phone and .NET comes with an object model that does this for you.

You can either locally install it, and then make a reference to it in your project:

Live_SDK_reference

Or you can get it all through Nuget:

LiveSDK_ Nuget

Under the hood this SDK of course still calls the REST service through HTTP, so you have to activate the Internet capability for your app (and make sure you publish a privacy policy):

Capabilities

Before you can use the API, your project needs to be associated with an app that is defined (not necessarily published) in the Store. This will update the manifest, and add an association file:

Associate

If you don’t associate your project with a Store app, then you may expect an exception:

App_not_configured

Before your user can access his OneDrive through your app, he or she needs to be authenticated. The following code calls the LiveAuthClient.LoginAsync method, which takes the list of scopes as a parameter. The scopes for this particular call include single sign-on, and read and write access to the OneDrive:

private async void SignIn_Executed()
{
    if (!this.isSignedIn)
    {
        try
        {
            LiveAuthClient auth = new LiveAuthClient();
            var loginResult = await auth.LoginAsync(new string[] { "wl.signin", "wl.skydrive", "wl.skydrive_update" });
            this.client = new LiveConnectClient(loginResult.Session);
            this.isSignedIn = (loginResult.Status == LiveConnectSessionStatus.Connected);
            await this.FetchfolderId();
        }
        catch (LiveAuthException ex)
        {
            Debug.WriteLine("Exception during sign-in: {0}", ex.Message);
        }
        catch (Exception ex)
        {
            // Get the code monkey's attention.
            Debugger.Break();
        }
    }
}

When the call executes, the system sign-in UI opens, unless the user has already signed into his Microsoft account and given consent for the app to use the requested scopes. In most situations, your end user is already logged in and will never have to type his user id and password, and he would see this consent screen only once:

Consent

The app then needs to create a working folder. I decided to just use the full name of the app itself as the name of the folder:

public string FolderName
{
    get { return Package.Current.Id.Name; }
}

Here’s how to create the folder -in the root of the user’s OneDrive- using a LiveConnectClient.PostAsync call:

private async void CreateFolder_Executed()
{
    try
    {
        // The overload with a String expects JSON, so this does not work:
        // LiveOperationResult lor = await client.PostAsync("me/skydrive", Package.Current.Id.Name);

        // The overload with a Dictionary accepts initializers:
        LiveOperationResult lor = await client.PostAsync("me/skydrive", new Dictionary<string, object>() { { "name", this.FolderName } });
        dynamic result = lor.Result;
        string name = result.name;
        string id = result.id;
        this.FolderId = id;
        Debug.WriteLine("Created '{0}' with id '{1}'", name, id);
    }
    catch (LiveConnectException ex)
    {
        if (ex.HResult == -2146233088)
        {
            Debug.WriteLine("The folder already existed.");
        }
        else
        {
            Debug.WriteLine("Exception during folder creation: {0}", ex.Message);
        }
    }
    catch (Exception ex)
    {
        // Get the code monkey's attention.
        Debugger.Break();
    }
}

The app needs to remember the id of the folder, because it is needed in the further calls. Therefore we store it in the roaming settings:

ApplicationDataContainer settings = ApplicationData.Current.RoamingSettings;
public string FolderId
{
    get { return this.settings.Values["FolderId"].ToString(); }
    private set { this.settings.Values["FolderId"] = value; }
}

In case you lose the folder id, you can fetch it with a LiveConnectClient.GetAsync call:

private async Task FetchfolderId()
{
    LiveOperationResult lor = await client.GetAsync("me/skydrive/files");
    dynamic result = lor.Result;
    this.FolderId = string.Empty;
    foreach (dynamic file in result.data)
    {
        if (file.type == "folder" && file.name == this.FolderName)
        {
            this.FolderId = file.id;
        }
    }
}

You can add files to the working folder with LiveConnectClient.BackGroundUploadAsync:

private async Task SaveAsFile(string content, string fileName)
{
    // String to UTF-8 Array
    byte[] byteArray = Encoding.UTF8.GetBytes(content);
    // Array to Stream
    MemoryStream stream = new MemoryStream(byteArray);
    // Managed Stream to Store Stream to File
    await client.BackgroundUploadAsync(
        this.FolderId,
        fileName,
        stream.AsInputStream(),
        OverwriteOption.Overwrite);
}

.Net developers would be tempted to apply Unicode encoding. Just hold your horses and stick to UTF-8. To convince you that it covers your needs, I added some French (containing accents and other decorations) and Chinese (containing whatever the Bing translator gave me) texts in the source code.

After clicking the ‘Save Files’ button in the sample app, the folder and its content become visible in the user’s File Explorer:

FileManager

Using LiveConnectClient.GetAsync you can read the folder’s content to enumerate the list of files in it:

private async void OpenFolder_Executed()
{
    try
    {
        // Don't forget '/files' at the end.
        LiveOperationResult lor = await client.GetAsync(this.FolderId + @"/files");
        dynamic result = lor.Result;
        this.files.Clear();
        foreach (dynamic file in result.data)
        {
            if (file.type == "file")
            {
                string name = file.name;
                string id = file.id;
                this.files.Add(new OneDriveFile() { Name = name, Id = id });
                Debug.WriteLine("Detected a file with name '{0}' and id '{1}'.", name, id);
            }
        }
    }
    catch (LiveConnectException ex)
    {
        Debug.WriteLine("Exception during folder opening: {0}", ex.Message);
    }
    catch (Exception ex)
    {
        // Get the code monkey's attention.
        Debugger.Break();
    }
}

The OneDriveFile class in this code snippet does not come from the API, but is just a lightweight custom class. My sample app is only interested in the name and id of each file, but the API has a lot more to offer:

/// <summary>
/// Represents a File on my OneDrive.
/// </summary>
public class OneDriveFile
{
    public string Name { get; set; }
    public string Id { get; set; }
}

After that OpenFolder call, the sample app displays the list of files:

onedrive_folder

With a file’s id, we can fetch its content through a LiveConnectClient.BackgroundDownloadAsync call:

private async void ReadFile_Executed()
{
    if (this.selectedFile != null)
    {
        // Don't forget '/content' at the end.
        LiveDownloadOperationResult ldor = await client.BackgroundDownloadAsync(this.selectedFile.Id + @"/content");
        // Store Stream to Managed Stream.
        var stream = ldor.Stream.AsStreamForRead(0);
        StreamReader reader = new StreamReader(stream);
        // Stream to UTF-8 string.
        this.SelectedText = reader.ReadToEnd();
    }
}

Here’s the result in the sample app:

onedrive_file

For the sake of completeness: LiveConnectClient also hosts asynchronous methods to move, copy, and delete files and folders.

This solution has many advantages:

  • You can store more data that the app’s roaming folder can handle.
  • The data is accessible across devices.
  • The end user is not confronted with logon screens or file pickers.
  • You don’t have to provide Cloud storage of your own.

There are some drawbacks too:

  • You’ll have to deal with the occasional latency, especially when uploading files to OneDrive.
  • If the client is not always connected, you might need a fallback mechanism to local storage (which uses a different file API).

Here’s the full source code of the sample app, it was created with Visual Studio 2013 for Windows 8.1. I cleared the app store association, so you’ll have to hook it to your own account: U2UC.WinRT.OneDriveSample.zip (5.1MB).

Enjoy!

Diederik