A BooleanToVisibilityConverter for WinRT 15 November 2011 Diederik-Krols Metro, WinRT This article describes a reversible boolean-to-visibility valueconverter for WinRT and Metro. [More]
A core MVVM framework for WinRT 27 October 2011 Diederik-Krols Metro, WinRT This article presents a core MVVM framework for building Metro applications on the WinRT runtime. With the WinRT runtime, Microsoft launched its fourth XAML-based platform - after WPf, Silverlight, and the Windows Phone. It's the fourth time they strongly advice development teams all over the world to get the maximum out of the power of XAML bindings, hence use the MVVM pattern in their applications. Strangely enough it's also the fourth time that they ship a runtime without the basic support for that same pattern. So it's up to the developers community to fill the gap. The gap will be filled rapidly. While Microsoft Patterns & Practice's Prism team is still hesitating, Laurent Bugnion with his MVVM Light Toolkit and Rob Eisenberg with Caliburn Micro are definitely going for a WinRT version of their popular frameworks. But we're not going to sit and wait for these frameworks, are we? We want to start developing MVVM applications (in Metro-speak they're called 'apps') here and now. In my ever humble opinion, the following three are the core requirements for using MVVM in an application : Raising the PropertyChanged event should be easy and typesafe. Defining a bindable command in a ViewModel should be easy and typesafe. Messaging between components should be easy and typesafe, and not create memory leaks. I gleaned a core MVVM-framework with just three files - one for each requirement: The namespace is Mvvm, so you can start each source code file with 'using Mvvm;'. Your manager will be impressed. Change Notification Most frameworks provide a base class that implements INotifyPropertyChanged. I'm a bit reluctant to use a scarse resource like inheritance- for such a triviality like just raising a standard event. Extension methods are much more flexible: namespace Mvvm { using System; using System.Collections.Generic; using System.Linq.Expressions; using Windows.UI.Xaml.Data; /// <summary> /// Generic extension methods used by the framework. /// </summary> public static class ExtensionMethods { /// <summary> /// Raises the PropertyChanged event. /// </summary> public static void Raise<T, P>(this PropertyChangedEventHandler pc, T source, Expression<Func<T, P>> pe) { if (pc != null) { pc.Invoke(source, new PropertyChangedEventArgs(((MemberExpression)pe.Body).Member.Name)); } } /// <summary> /// Raises the PropertyChanged event for all properties. /// </summary> public static void RaiseAll<T>(this PropertyChangedEventHandler pc, T source) { if (pc != null) { pc.Invoke(source, new PropertyChangedEventArgs(string.Empty)); } } } } Here's how a typical property looks like in a viewmodel or a model that implements INotifyPropertyChanged. Broadcasting a property value change is easy, ànd you get Intellisense support: private string message public string Message { get { return this.message; } set { this.message = value; this.PropertyChanged.Raise(this, o => o.Message); } } It also definitely makes a good candidate for a code snippet... Command binding Most frameworks have an implementation of ICommand to be used specifically in viewmodels. Microsoft's RoutedCommand makes no sense there. Caliburn uses a radically different paradigm based on triggers and actions - the result is the same but it's further away from MVVM. The ICommand implementations in Prism and MVVM Light Toolkit have a constructor with just delegates for the Executed and CanExecute members. I prefer the RelayCommand implementation of the MVVM Light Toolkit, but I also prefer to call it DelegateCommand (sorry, Laurent) - the Prism terminology. It's easy to use and it comes with a generic version: namespace Mvvm { using System; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using Windows.UI.Xaml.Input; using EventHandler = Windows.UI.Xaml.EventHandler; public class DelegateCommand : ICommand { private readonly Action _execute; private readonly Func<bool> _canExecute; /// <summary> /// Initializes a new instance of the DelegateCommand class that /// can always execute. /// </summary> /// <param name="execute">The execution logic.</param> /// <exception cref="ArgumentNullException">If the execute argument is null.</exception> public DelegateCommand(Action execute) : this(execute, null) { } /// <summary> /// Initializes a new instance of the DelegateCommand class. /// </summary> /// <param name="execute">The execution logic.</param> /// <param name="canExecute">The execution status logic.</param> /// <exception cref="ArgumentNullException">If the execute argument is null.</exception> public DelegateCommand(Action execute, Func<bool> canExecute) { if (execute == null) { throw new ArgumentNullException("execute"); } _execute = execute; _canExecute = canExecute; } /// <summary> /// Occurs when changes occur that affect whether the command should execute. /// </summary> public event EventHandler CanExecuteChanged; /// <summary> /// Raises the <see cref="CanExecuteChanged" /> event. /// </summary> [SuppressMessage("Microsoft.Design", "CA1030:UseEventsWhereAppropriate", Justification = "This cannot be an event")] public void RaiseCanExecuteChanged() { var handler = CanExecuteChanged; if (handler != null) { handler(this, EventArgs.Empty); } } /// <summary> /// Defines the method that determines whether the command can execute in its current state. /// </summary> /// <param name="parameter">This parameter will always be ignored.</param> /// <returns>true if this command can be executed; otherwise, false.</returns> [DebuggerStepThrough] public bool CanExecute(object parameter) { return _canExecute == null ? true : _canExecute(); } /// <summary> /// Defines the method to be called when the command is invoked. /// </summary> /// <param name="parameter">This parameter will always be ignored.</param> public void Execute(object parameter) { if (CanExecute(parameter)) { _execute(); } } } } Here's how to use the DelegateCommand. The ViewModel defines a command by providing just delegates, and provides implementations: public ICommand UpdateTextCommand { get { return new DelegateCommand(this.UpdateTextCommand_Executed); } } private void UpdateTextCommand_Executed() { // Command Logic } The View can bind to that command in XAML, no code-behind is needed: <Button Content="Update Text" Command="{Binding UpdateTextCommand}" /> Event Aggregation In an application that consists of different loosely-coupled components that need to publish and subscribe to events, it's not a good idea to rely on regular .NET events. More info can be found here. A so-called event aggregator is a much better solution. Prism's event aggregator may be the most powerful on the market, but the one from Caliburn Micro is easier to extract out of its framework. I just added the singleton pattern because I don't want to introduce an Inversion-of-Control container and bootstrappers in my three-file-framework. Here's the full code of the Event Aggregator: namespace Mvvm { using System; using System.Collections.Generic; using System.Linq; using System.Reflection; /// <summary> /// A marker interface for classes that subscribe to messages. /// </summary> public interface IHandle { } /// <summary> /// Denotes a class which can handle a particular type of message. /// </summary> /// <typeparam name = "TMessage">The type of message to handle.</typeparam> public interface IHandle<TMessage> : IHandle { /// <summary> /// Handles the message. /// </summary> /// <param name = "message">The message.</param> void Handle(TMessage message); } /// <summary> /// Enables loosely-coupled publication of and subscription to events. /// </summary> public interface IEventAggregator { /// <summary> /// Gets or sets the default publication thread marshaller. /// </summary> /// <value> /// The default publication thread marshaller. /// </value> Action<System.Action> PublicationThreadMarshaller { get; set; } /// <summary> /// Subscribes an instance to all events declared through implementations of <see cref = "IHandle{T}" /> /// </summary> /// <param name = "instance">The instance to subscribe for event publication.</param> void Subscribe(object instance); /// <summary> /// Unsubscribes the instance from all events. /// </summary> /// <param name = "instance">The instance to unsubscribe.</param> void Unsubscribe(object instance); /// <summary> /// Publishes a message. /// </summary> /// <param name = "message">The message instance.</param> /// <remarks> /// Uses the default thread marshaller during publication. /// </remarks> void Publish(object message); /// <summary> /// Publishes a message. /// </summary> /// <param name = "message">The message instance.</param> /// <param name = "marshal">Allows the publisher to provide a custom thread marshaller for the message publication.</param> void Publish(object message, Action<System.Action> marshal); } /// <summary> /// Enables loosely-coupled publication of and subscription to events. /// </summary> public class EventAggregator : IEventAggregator { /// <summary> /// The default thread marshaller used for publication; /// </summary> public static Action<System.Action> DefaultPublicationThreadMarshaller = action => action(); private static IEventAggregator instance; readonly List<Handler> handlers = new List<Handler>(); /// <summary> /// Initializes a new instance of the <see cref = "EventAggregator" /> class. /// </summary> public EventAggregator() { PublicationThreadMarshaller = DefaultPublicationThreadMarshaller; } /// <summary> /// Gets the singleton instance. /// </summary> public static IEventAggregator Instance { get { if (instance == null) { instance = new EventAggregator(); } return instance; } } /// <summary> /// Gets or sets the default publication thread marshaller. /// </summary> /// <value> /// The default publication thread marshaller. /// </value> public Action<System.Action> PublicationThreadMarshaller { get; set; } /// <summary> /// Subscribes an instance to all events declared through implementations of <see cref = "IHandle{T}" /> /// </summary> /// <param name = "instance">The instance to subscribe for event publication.</param> public virtual void Subscribe(object instance) { lock (handlers) { if (handlers.Any(x => x.Matches(instance))) return; handlers.Add(new Handler(instance)); } } /// <summary> /// Unsubscribes the instance from all events. /// </summary> /// <param name = "instance">The instance to unsubscribe.</param> public virtual void Unsubscribe(object instance) { lock (handlers) { var found = handlers.FirstOrDefault(x => x.Matches(instance)); if (found != null) handlers.Remove(found); } } /// <summary> /// Publishes a message. /// </summary> /// <param name = "message">The message instance.</param> /// <remarks> /// Does not marshall the the publication to any special thread by default. /// </remarks> public virtual void Publish(object message) { Publish(message, PublicationThreadMarshaller); } /// <summary> /// Publishes a message. /// </summary> /// <param name = "message">The message instance.</param> /// <param name = "marshal">Allows the publisher to provide a custom thread marshaller for the message publication.</param> public virtual void Publish(object message, Action<System.Action> marshal) { Handler[] toNotify; lock (handlers) toNotify = handlers.ToArray(); marshal(() => { var messageType = message.GetType(); var dead = toNotify .Where(handler => !handler.Handle(messageType, message)) .ToList(); if (dead.Any()) { lock (handlers) { dead.Apply(x => handlers.Remove(x)); } } }); } protected class Handler { readonly WeakReference reference; readonly Dictionary<TypeInfo, MethodInfo> supportedHandlers = new Dictionary<TypeInfo, MethodInfo>(); public Handler(object handler) { reference = new WeakReference(handler); var handlerInfo = typeof(IHandle).GetTypeInfo(); var interfaces = handler.GetType().GetTypeInfo().ImplementedInterfaces .Where(x => handlerInfo.IsAssignableFrom(x.GetTypeInfo()) && x.IsGenericType); foreach (var @interface in interfaces) { var type = @interface.GenericTypeArguments[0]; var method = @interface.GetTypeInfo().DeclaredMethods.First(x => x.Name == "Handle"); supportedHandlers[type.GetTypeInfo()] = method; } } public bool Matches(object instance) { return reference.Target == instance; } public bool Handle(Type messageType, object message) { var target = reference.Target; if (target == null) return false; var typeInfo = messageType.GetTypeInfo(); foreach (var pair in supportedHandlers) { if (pair.Key.IsAssignableFrom(typeInfo)) { pair.Value.Invoke(target, new[] { message }); return true; } } return true; } } } /// <summary> /// Generic extension methods used by the framework. /// </summary> public static class EventAggregatorExtensionMethods { /// <summary> /// Applies the action to each element in the list. /// </summary> /// <typeparam name="T">The enumerable item's type.</typeparam> /// <param name="enumerable">The elements to enumerate.</param> /// <param name="action">The action to apply to each item in the list.</param> public static void Apply<T>(this IEnumerable<T> enumerable, Action<T> action) { foreach (var item in enumerable) action(item); } } } Here's how to use it. Please note that I'm just passing messages of type String, you might want to define your own event payload classes. A publisher just needs to get a reference to the central even handler, and publish its message: EventAggregator.Instance.Publish(this.Message); The subscriber registers himself to the same event aggregator. He specifies the type of message he's interested in by implementing the IHandle<T> interface: class SubscriberViewModel : INotifyPropertyChanged, IHandle<string> { public SubscriberViewModel() { // Subscribe EventAggregator.Instance.Subscribe(this); } public void Handle(string message) { // Event handling comes here } } Publisher and subscriber never have a reference to each other, while the event aggregator uses weak references. This results in a memory-leak free pattern. Sample I built a small and simple application (oops, I did it again: app) to test drive the framework. Here's how it looks like: On the left side of the screen, there's a text balloon and a button. These belong to the publisher. Clicking the button updates the Message property and via the change notification extension methods also the GUI. It sends the new value as message through the event aggregator. The text balloon in the middle belongs to a subscriber that is instantiated using a view-first approach: the view instantiates its viewmodel. Typically this is done by defining its data context in XAML - but that does not seem to work yet, so I needed some code behind. The text balloon on the right belongs to another subscriber. This one is instantiated using the viewmodel-first approach. When the datacontext of a control is set to a viewmodel, the control decides what template to load. This is typically done with typed data templates in WPF, or with a value converter in Silverlight. Since typed data templates are not available in Metro, I used the Silverlight approach. [Note: The IValueConverter interface in Metro is different from its predecessors.] Both subscribers receive the message through the event aggregator subscription, and use the change notification extensions methods it to update their own Message property, populating the text balloon. Source Code Here's the full source code. It requires VS 2011 Developer Preview: U2UConsult.WinRT.MVVM.zip (205,86 kb) Enjoy!
File IO in Windows 8 14 October 2011 Michael-Van-Wesemael Windows 8, XAML, Metro Let’s leave Windows Phone for a moment, and let’s have a look at Windows 8. Recently the U2U-team was present at the Microsoft Build-convention in Anaheim, California, where Microsoft unveiled Windows 8. Now, what we saw is still just a preview, but it clearly shows the direction in which Windows is evolving. Have a look at this video, to see Windows 8 in action : The “new style” applications Windows 8 offers are “Metro”-applications (yes, like in Windows Phone Metro style), and these can be made using Xaml and managed code, or even using HTML5 + Javascript. Metro-apps will have to be installed through a marketplace, and are kind of sandboxed (Comparable to Silverlight, but different ;-) ). One of the effects of this sandboxing is that your options for working with files are limited. You cannot just access any folder on your machine ! Unfortunately you’re also unable to use Isolated Storage. So what can you use ? Let’s start by writing info into the “Local Folder”. Windows.Storage.ApplicationData appData = Windows.Storage.ApplicationData.Current; StorageFile file = await appData.LocalFolder.CreateFileAsync("EmployeeList.u2u"); Windows.Storage.Streams.IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.ReadWrite); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } No ordinary File here, but a StorageFile which I have to open to write in. The IRandomAccessStream I get back gives me the possibility to create an input- (for reading) or output-stream (for writing). IOutputStream output = stream.GetOutputStreamAt(0); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } And then I got stuck. The IOutputStream gives me a WriteAsync-function, but it ask me for an IBuffer-object. How to write data ? Luckily there’s already some MSDN-documentation available. That tells me to use a DataWriter which takes the IOutputStream as a constructor-argument. DataWriter writer = new DataWriter(output); writer.WriteString("HERE GOES DATA"); output.FlushAsync(); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } Not there yet ! The code I wrote starts fro; the assumption that File IO is much like the “ordinary” file IO: flush the stream and done. In Metro we have to ”commit” the data in the writer, and I have to start the flushing, so this is the working code : 1: DataWriter writer = new DataWriter(output); 2: writer.WriteString("HERE GOES DATA"); 3: 4: await writer.StoreAsync(); 5: output.FlushAsync().Start(); 6: statusTxt.Text = "File Saved"; .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } They could have made it simpler . By localfolder I assumed the bin/debug-folder. Nothing there. It seems my file is located in C:\Users\michael\AppData\Local\Packages\d64899f1-9800-470a-9cb3-fa89210f4941_qs0a8q7rnpy8j\LocalState. How about reading the file ? Well, simply reverse your writing-logic (writer becomes reader, output becomes input, store becomes load, …) 1: Windows.Storage.ApplicationData appData = Windows.Storage.ApplicationData.Current; 2: 3: var file = await appData.LocalFolder.GetFileAsync("EmployeeList.u2u"); 4: Windows.Storage.Streams.IRandomAccessStream stream = await file.OpenAsync(FileAccessMode.Read); 5: 6: IInputStream input = stream.GetInputStreamAt(0); 7: 8: DataReader reader = new DataReader(input); 9: 10: var size = stream.Size; 11: await reader.LoadAsync((uint)size); 12: var data = reader.ReadString((uint)size); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } There you go! What about other folders than the “local” ? The KnownFolders=clqss gives me access to following locations : Documents Library Home Group Media Server Devices (DLNA – Digital Living Network Alliance Devices, sounds interesting) MusicLibrary Pictures Library Removable Devices Videos Library Let’s change the first 2 lines of my writing-code for using the documents library : StorageFolder doclib = Windows.Storage.KnownFolders.DocumentsLibrary; StorageFile file = await doclib.CreateFileAsync("EmployeeList.u2u"); .csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, "Courier New", courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; } As soon as you start running your code, it will fail on the first line (no exception though, simply stops). That’s because you explicitly have to give the app the capability to access the Document library. Double-clicking on Package.appxmanifest allows you to do that : Still: this time your app will stop on the second line. You also need to associate your app with the u2u-fileextension. This is also done in the appxmanifest-file in the declarations-tab where we add a filetype association declaration : There you go: the app works and saves my u2u-file in the doclibrary. Tweet