All posts by weston

Introducing SortingObservableCollection

ObservableCollections are awesome. The two way binding lets your user seamlessly update your model and any programmatic changes to the model will be seamlessly reflected in the view.

I wanted one that kept it’s items in order, no matter what. It should maintain order as items are added and watch them via INotifyPropertyChanged to move them automatically. So here it is on CodePlex and NuGet. Sample usage is:

var collection = new SortingObservableCollection<MyViewModel, int>(Comparer<int>.Default, model => model.IntPropertyToSortOn);

collection.Add(new MyViewModel(3));
collection.Add(new MyViewModel(1));
collection.Add(new MyViewModel(2));

// At this point, the order is 1, 2, 3

collection[0].IntPropertyToSortOn = 4;
// As long as IntPropertyToSortOn uses INotifyPropertyChanged, this will cause the collection to resort correctly

The Hidden “gotcha” in Windows Store App Lifecycle

The application lifecycle diagram from MSDN:

Diagram

Pretty simple, but that Resuming bit is the “gotcha”. MSDN doesn’t really explain how this lifecycle relates to code as much as I’d like, so I’ll write it in layman’s terms:

  • For your Application class:
    • OnLaunched will be called any time your app is not in memory or if the app is being asked open something (see the ActivationKind enum)
    • The Suspending event will fire whenever your app leaves the view
    • The Resuming event will fire whenever your app re-enters the view, only if OnLaunched wouldn’t be called
  • For the Page class:
    • OnNavigatedTo will be called whenever someone calls Frame.Navigate with your page. This could be explicitly via a code-behind call, or implicitly via a call from the SuspensionManager helper class
    • OnNavigatedFrom will be called whenever your app leaves the view by the SuspensionManager (in sync with the Application’s Suspending event)

(NOTE: Visual Studio’s templates come with the NavigationHelper.cs class. You’re encouraged to ignore the OnNavigatedTo and OnNavigatedFrom overrides, instead using NavigationHelper’s LoadState and SaveState events)

You should see one basic thing missing from Page. It can’t know about the Resuming lifecycle event. This creates a bit of an awkward situation. Let’s say you’re in MainPage.xaml.cs and you need to register for some events on OnNavigatedTo with an object that you were passed as a navigation parameter. If you don’t de-register these events on OnNavigatedFrom, you’ll be sorry. It’s possible for another call to OnNavigatedTo to occur on the same instance of MainPage — you’ll register for the same event twice which is probably not what you expected.

So OK, de-register your events in OnNavigatedFrom. But wait, that doesn’t quite work either! Remember that OnNavigatedFrom is called every time your app leaves the view, but OnNavigatedTo might not be called when it returns. You’ll end up without event handlers if the user leaves the app then returns while it’s still in memory (extremely common case).

So what do you do?

Honestly, the Page class isn’t enough. We need to extend it. Try something like this:


/// <summary>
/// Use in place of the Page class for better application lifecycle support and better
/// code reuse.
/// </summary>
public class BasicPage : Page
{
    #region Public Properties

    /// <summary>
    /// Reference to the underlying NavigationHelper, which can be accessed by the Application.
    /// </summary>
    public NavigationHelper NavigationHelper { get; private set; }

    /// <summary>
    /// Use for the DataContext.
    /// </summary>
    public ObservableDictionary DefaultViewModel { get; private set; }

    #endregion

    #region Constructors

    /// <summary>
    /// Inheriting classes should call InitializeComponent().
    /// </summary>
    public BasicPage()
    {
        NavigationHelper = new NavigationHelper(this);
        NavigationHelper.LoadState += LoadState;
        NavigationHelper.SaveState += SaveState;
        NavigationHelper.ResumeState += ResumeState;

        DefaultViewModel = new ObservableDictionary();
    }

    #endregion

    #region Protected methods

    /// <summary>
    /// Called when this page should initialize it's data for the first time. Register event handlers.
    /// </summary>
    protected virtual void LoadState(object sender, LoadStateEventArgs e)
    {

    }

    /// <summary>
    /// Called when this page should save it's data to disk in preparation for leaving memory. Deregister
    /// event handlers.
    /// </summary>
    protected virtual void SaveState(object sender, SaveStateEventArgs e)
    {

    }

    /// <summary>
    /// Called when this page has returned to the view. Register event handlers if necessary or update the view.
    /// </summary>
    protected virtual void ResumeState(object sender)
    {

    }

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
        NavigationHelper.OnNavigatedTo(e);
    }

    protected override void OnNavigatedFrom(NavigationEventArgs e)
    {
        NavigationHelper.OnNavigatedFrom(e);
    }

    #endregion
}

The basic mechanics for how to hook up a BasicPage like this can be found in a similar blog post. The only real difference between the above example and the linked one is the ResumeState method. This requires a modification to NavigationHelper.cs as well. Add the following:

/// <summary>
/// Register this event on the current page to react to the app coming
/// back into view. This event and LoadState are mutually exclusive,
/// you will never get both.
///
/// You should only need to do view updates, as everything should still
/// be in-memory when this event is called.
/// </summary>
public event ResumeStateEventHandler ResumeState;

...

/// <summary>
/// Invoked when the app is resuming.
/// </summary>
public void OnResuming()
{
    if (this.ResumeState != null)
    {
        this.ResumeState(this);
    }
}

The final hook is in your App.xaml.cs code-behind, you need to register for the Resuming event and pass it to the page:

this.Resuming += OnResuming;

...

private void OnResuming(object sender, object e)
{
    Frame f = Window.Current.Content as Frame;
    BasicPage p = f.Content as BasicPage;

    if (p != null)
    {
        p.NavigationHelper.OnResuming();
    }
    else
    {
        throw new Exception("Every page must implement BasicPage!");
    }
}

Now you have the tools you need with minimal code reuse.

Not so Stupid Simple Logging for Windows Store Apps in C#/VB

The last time that I had to worry about logging was within Azure. My cloud solution was simple, and thus my logging solution was simple. Lately, the application I’ve been building for Windows 8.1 is not simple. It’s one of the most complex apps I’ve built to date.

It’s no secret that log4net won’t work in a Windows Store app, but that’s OK. There’s a different way to think about logging, and that’s with Event Tracing for Windows (here’s a complex, but good MSDN article). ETW logging is an obvious choice when developing on Windows as it guarantees:

  • Extremely fast performance (~16us per log event)
  • Application will not change behavior when logging is ON vs. OFF

The latter is very important. Imagine that you’re tracking down a race condition and you’re using a custom logging solution. You turn on logging, and it no longer reproduces! How could this happen? Your logging solution might cause the processor to schedule work differently when it’s ON vs. OFF.

First, if you’re looking for simple…

If you’re looking for a simple logging solution for Windows Store apps (regardless of language), look no further than Windows.Foundation.Diagnostics (new in Windows 8.1). Don’t be let astray by the first Google hit for “windows store” logging. While that solution uses the same methods I’ll expand on in this post, it will introduce more complexity that you’re looking for. It was also written before Windows.Foundation.Diagnostics became available in Windows 8.1.

The Windows.Foundation.Diagnostics namespace contains LoggingChannel and LoggingSession, which will likely fulfill your simple logging needs. Use LoggingChannel’s LogMessage(string) and LogValuePair(string, int) for simple string logging. There’s a wonderful Channel9 video on how to setup LoggingChannels with LoggingSessions.

If you’re OK with simple string logging and logs being saved to .ETL files, Windows.Foundation.Diagnostics is probably perfect for you.

But what if…?

I recently discovered that there’s more to life than simple string logging. That’s the “event” portion of ETW. I was raised to think of logging that looks like this:

Log.Verbose("Application starting");

In ETW-speak, this lets you log a Verbose event with a string parameter. Very powerful because that string can be anything. However, consider this:

Log.ApplicationStarting();

In a nutshell, that’s what ETW means by “event”. Both of the above log statement have the same purpose. They want to log that the application has started. The second statement is scale-able. The first one is not.

By scale-able, I mean that down the road, you might want to log more than just “Application starting” on boot. Maybe you want to know what platform and version of the code is starting. You could go change to:

Log.Verbose(string.Format("Application starting on {0} with version {1}", App.Platform.ToString(), App.Version.ToString()));

And that would be fine, except if you had multiple places in your app where you needed to log this event (OK, maybe app start is a bad example since you’ll probably only call it from one place, but you can imagine). Then you’d be copy & pasting log lines and that goes against the gospel of computer science.

So, you should centralize your events! That way, your event can really be as descriptive as you’d like. If it needs contextual data, you can just pass in the raw object instead of having to format it at the logging location.

Enter EventSource

.NET 4.5.1’s System.Diagnostics.Tracing namespace provides EventSource. It’s the simplest way to create ETW events in .NET. Check out the second example on the MSDN page for how to write it.

EventSource isn’t perfect though. You can only pass simple types like string and int to event methods. It cannot implement any interfaces. You’re probably going to want to wrap EventSource in another class like so:

public class LifecycleEventSourceWrapper
{
    public LifecycleEventSource EventSource {get; private set;}

    public LifecycleEventSourceWrapper()
    {
        EventSource = new LifecycleEventSource();
    }

    public void ApplicationStarting()
    {
        // Get app version
        var v = Package.Current.Id.Version;
        string version = string.Format("{0}.{1}.{2}.{3}", v.Major, v.Minor, v.Build, v.Revision);

        string platform = // get the platform

        EventSource.ApplicationStarting(version, platform);
    }
}

public class LifecycleEventSource : EventSource
{
    [Event(1, Message = "App starting on {0} with version {1}")]
    public void ApplicationStarting(string version, string platform)
    {
        if (this.IsEnabled()) this.WriteEvent(1, version, platform);
    }
}

Notice that I created LifecycleEventSource, and not just MyAppEventSource, implying that LifecycleEventSource should only be use for logging events related to application lifecycle. This is a powerful pattern because you can later filter your logs much more easily.

Check out MSDN for all the other awesome things that EventSource can do (like keywords and opcodes). You may not need them now, but they’re available for later use.

Cool, you’ve sold me on EventSource. So I’m done?

Not quite. Nobody is listening for these events. If you want to use another program like Windows Performance Analyzer to listen, then you actually are done, but you probably wanted to write to a file.

Assuming you want to do this all in one process, this is where the EventListener is used. There don’t appear to be any awesome examples that you can just drop in, so here’s an extremely basic one that keeps an in-memory cache of log lines, then writes them to a text file in your local storage folder every 5 seconds:

public class FileEventListener : EventListener
{
    private object syncObj = new object();
    private List<string> logLines;
    private StorageFile logFile;
    private ThreadPoolTimer periodicTimer;

    public FileEventListener()
    {
        logLines = new List<string>();
    }

    // Should be called right after the constructor (since constructors can't have async calls)
    public async Task InitializeAsync()
    {
        logFile = await ApplicationData.Current.LocalFolder.CreateFileAsync("logs.txt", CreationCollisionOption.OpenIfExists);

        // We don't want to write to disk every single time a log event occurs, so let's schedule a
        // thread pool task
        periodicTimer = ThreadPoolTimer.CreatePeriodicTimer((source) =>
            {
                // We have to lock when writing to disk as well, otherwise the in memory cache could change
                // or we might try to write lines to disk more than once
                lock (syncObj)
                {
                    if (logLines.Count > 0)
                    {
                        // Write synchronously here. We'll never be called on a UI thread and you
                        // cannot make an async call within a lock statement
                        FileIO.WriteLinesAysnc(logFile, logLines).AsTask().Wait();
                        logLines = new List<string>();
                    }
                }
            }, TimeSpan.FromSeconds(5));
    }

    protected override void OnEventWritten(EventWrittenEventArgs eventData)
    {
        // This could be called from any thread, and we want our logs in order, so lock here
        lock (syncObj)
        {
            string payload = string.Format(eventData.Message, eventData.Payload.ToArray());
            logLines.Add(string.Format("{0}\t{1}", DateTime.Now.ToString(), payload));
        }
    }
}

You’ll need to hook EventSource to EventListener of course. I generally do this in the constructor of a class that exposes all of my EventSources.

Now what?

Now that you’ve got logs in a file form, you could ask users to send them to you when they report a bug, or you could upload them to cloud storage for the user (but be sure to discuss this in the privacy policy!).

4 Things to know about SuspensionManager

The default Visual C# app templates created by VS in Windows 8.1 make use of the SuspensionManager helper class (in the Common folder) to handle how your app can save it’s state when Windows puts it in the Suspended state. As you might expect, it serializes your data to disk, then deserializes it back for you when your app Resumes. How? DataContractSerializer. It’s a good way. Here’s what you need to know:

  1. DataContractSerializer (and thus SuspensionManager) needs to know about any custom types before it can work with your objects. Tell it in your App() constructor via:
    SuspensionManager.KnownTypes.Add(typeof(ObservableCollection<CarViewModel>));
    SuspensionManager.KnownTypes.Add(typeof(CarViewModel));
    
  2. Types serialized by DataContractSerializer must be decorated with the DataContractAttribute.
    [DataContract]
    public CarViewModel { ... }
    
  3. Member fields/properties of these types must be decorated with the DataMemberAttribute. By default, none of your objects members are serialized, you must use the attribute to include them. The cool thing is, you can apply it to a private member.
  4. When deserializing, the default constructor of your object will not be called. Weird, seemingly illegal, but it makes sense — say your object contains a state machine, and the default constructor sets the state machine to position 0. If you serialize your object with the state machine at position 3, you want it to deserialize in the same position.

If your types can deal with the constructor not being called, easy-as-pie, you are done! But, what if you need to run initialization logic on deserialization? For example, my CarViewModel has a private Car field. All of my public properties are simply meta-data based off of the Car. It’s more convenient for me to simply serialize only the Car, then re-initialize my meta-data once the Car is returned to me in deserialization.

Have no fear, just use the OnDeserializedAttribute above a method, like so:

[OnDeserialized]
internal void Initialize(StreamingContext context)
{
    // this.car is already in place, we've been deserialized
    InitializeDataFromCar(this.car);
}

Need more access? No problem, you’ve got an attribute for before serialization, after serialization, before deserialization, and after deserialization. You can find them all under the System.Runtime.Serialization namespace.

Making Blend Designer work with sample data

When you open a *.xaml file, VisualStudio automatically opens a Design view that’s powered by Expression Blend. The idea is to be able to preview/design your UI with XAML without ever having to run the app (or at least not run it as frequently). It’s a huge time saver, but unless your statically assigning values to your XAML components instead of binding to them, it’s not super intuitive to make Blend pull in sample data values at design time. The best documentation I could find for it was for Silverlight.

The Design tab, showing a grouped GridView, filled with data.
The Design tab, showing a grouped GridView, filled with design-time sample data.

So let’s fill those GridViews with data! There are a few ways to go about it. If you were to create a new Windows Store app based on the Grid App template (Boot VS -> New Project… -> Visual C# -> Windows Store -> Grid App (XAML)), you’d see one way of it working:


<CollectionViewSource
    x:Name="groupedItemsViewSource"
    Source="{Binding Groups}"
    IsSourceGrouped="true"
    ItemsPath="Items"
    d:Source="{Binding Groups, Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"/>

The d namespace qualifier is at the heart of this — above you’ll see it defined as:

xmlns:d="http://schemas.microsoft.com/expression/blend/2008"

The “blend” in the name tips you off that this is the design namespace. It does not impact running code. So when they said

d:Source="{Binding Groups, Source={d:DesignData Source=/DataModel/SampleData.json, Type=data:SampleDataSource}}"

this is the mechanism for supplying the design data. Go ahead, misspell the path to SampleData.json. The app runs fine, but the Design tab no longer shows data in the GridView.

d:DesignData

DesignData is mode #1. Given:

  • A data file (both XAML and JSON files seem to work)
    • /DataModel/SampleData.json
  • A Type
    • SampleDataSource

Blend is smart enough to populate the GridView with data at this point. XAML data files are strongly typed, but as long as the JSON values have the same name/type as your ViewModel object, it’ll parse in just fine.

This method is OK, but I don’t really fancy it. It requires your sample data file to be directly mapped to Properties on your ViewModel. Unless your service happens to be outputting JSON that’s just perfect for you, your ViewModel will probably differ. Also, if you’re into MVVM, your data is probably coming from a ServiceProvider, and you probably have an interface defining your service calls. This lines itself up perfectly for run-time mocking with sample data, so why not use the same technique for design time?

d:DesignInstance

DesignInstance is mode #2. Essentially, it’s a way of telling Blend, “Hey, I’ve got an object here that you can call the default constructor on when the app’s not running and you can use it to bind”. For the same CollectionViewSource as above:

d:Source="{Binding Groups, Source={d:DesignInstance Type=data:SampleDataDesigner, IsDesignTimeCreatable=True}}"

This corresponds to the following class (a refactored verson of the SampleDataSource class in the Grid app template):

public class SampleDataDesigner
{
    public ObservableCollection<SampleDataGroup> Groups { get; private set; }

    public SampleDataDesigner()
    {
        Groups = new ObservableCollection<SampleDataGroup>();

        Task.Run(async () =>
            {
                await GetGroupsAsync();
            }).Wait();
    }

    private async Task<IEnumerable<SampleDataGroup>> GetGroupsAsync()
    {
        await GetSampleDataAsync();

        return Groups;
    }

    private async Task GetSampleDataAsync()
    {
        if (Groups.Count != 0)
            return;

        Uri dataUri = new Uri("ms-appx:///DataModel/SampleData.json");

        StorageFile file = await StorageFile.GetFileFromApplicationUriAsync(dataUri);
        string jsonText = await FileIO.ReadTextAsync(file);
        JsonObject jsonObject = JsonObject.Parse(jsonText);
        JsonArray jsonArray = jsonObject["Groups"].GetArray();

        foreach (JsonValue groupValue in jsonArray)
        {
            JsonObject groupObject = groupValue.GetObject();
            SampleDataGroup group = new SampleDataGroup(groupObject["UniqueId"].GetString(),
                                                        groupObject["Title"].GetString(),
                                                        groupObject["Subtitle"].GetString(),
                                                        groupObject["ImagePath"].GetString(),
                                                        groupObject["Description"].GetString());

            foreach (JsonValue itemValue in groupObject["Items"].GetArray())
            {
                JsonObject itemObject = itemValue.GetObject();
                group.Items.Add(new SampleDataItem(itemObject["UniqueId"].GetString(),
                                                   itemObject["Title"].GetString(),
                                                   itemObject["Subtitle"].GetString(),
                                                   itemObject["ImagePath"].GetString(),
                                                   itemObject["Description"].GetString(),
                                                   itemObject["Content"].GetString()));
            }
            this.Groups.Add(group);
        }
    }
}

At first, this doesn’t seem like a very large improvement, but remember, you should be using a ServiceProvider:

public class SampleDataDesigner
{
    public ObservableCollection<SampleDataGroup> Groups { get; private set; }

    public SampleDataDesigner()
    {
        Task.Run(async () =>
            {
                IDataService service = ServiceProvider.Current.GetService(typeof(IDataService)) as IDataService;
                Groups = await service.GetGroupsAsync();
            }).Wait();
    }
}

Much, much simpler. You get to share code that populates your Design view, populates your app in a sample-data mode, and probably populates your unit tests.

Oh, and one more thing. If you need to tell (in code) whether the instance has been started by the Blend Designer or not, use DesignModeEnabled.