MVP Monday - Shared Code for Windows 8 and Windows Phone8

 

Editor’s note: The following post was written by Silverlight MVP Jeremy Likness

 

The end of October 2012 marked a major set of milestones for Microsoft’s mobile computing story. Consumers learned about the availability of Windows 8 just days before the details about Windows Phone 8 and the developer SDK were revealed. It is now possible to build code for both platforms. With an amazing feature known as the Portable Class Library (PCL) it is also possible to share a significant amount of code between platforms. In this blog post, I’ll show you how with an example that uses the Model-View-ViewModel (MVVM) pattern to fetch the contents of a web page and present it as both a Windows Store app and a Windows Phone 8 app without any code-behind.

 

 

 The last statement is important. While I don’t necessarily strive to eliminate code-behind in my apps, this example will demonstrate just how much can truly be shared across platforms. By building a portable library to perform most of the work, the only effort involved in launching the native applications is creating a view and connecting the view model. That’s it! What is even more powerful is that fact that these libraries can be shared with other platforms as well, including the desktop-based Windows Presentation Foundation (WPF) and Silverlight.

 

Getting started is as simple as creating a new project (CTRL+SHIFT+N for the keyboard-inclined). Navigate from “Visual C#” to“Windows” and then select “Portable Class Library.” I named the project“CommonLibrary” and the first step was to select the target platforms. In this case I chose the latest .NET Framework, Windows Store apps, and Windows Phone 8.

 

Once the target platforms are selected, the Portable Class Library will automatically create a special set of references that only work for that specific combination of platforms. It does this using a feature referred to as an “Extension SDK” that is new to Visual Studio 2012. These special SDKs allow multiple sets of assemblies and other metadata to be provided. In the case of the Portable Class Library, that data is the set of assemblies and APIs that are common to the platforms you select. It’s like having a special set of references that prevent you from doing anything not supported by any of the platforms you are trying to target.

 

You can learn more about how the PCL works “behind the scenes” by reading my blog series Understanding the Portable Library by Chasing ICommand. What’s important to know is that the common APIs are quite rich and allow you to create a common code base that can be referenced from the target frameworks without recompiling. To see just how rich this set of common features is, I created an MVVM implementation that takes a URL, validates the URL, and then fetches the content of a web page –all in a shared assembly!

 

 

The most basic support PCL provides is for MVVM constructs such as property change notification and commands. For example, I can define a generic command that allows me to set an action and a predicate to determine whether or not the action can be executed like this:

 

publicclassActionCommand : ICommand

{

    privatereadonlyAction<object> _action;

    privatereadonlyPredicate<object> _canExecute;

 

    public ActionCommand()

    {

        _action = _action ?? (obj => { });

        _canExecute = _canExecute ?? (obj => true);

    }

 

    publicActionCommand(Action<object> action) : this()

    {

        _action = action;

    }

 

   publicActionCommand(Action<object> action, Predicate<object> condition) : this(action)

    {

        _canExecute = condition;

    }

 

   publicboolCanExecute(object parameter)

    {

        return _canExecute(parameter);

    }

 

    publicvoid Execute(object parameter)

    {

        _action(parameter);

    }

 

    publicvoidOnCanExecuteChanged()

    {

        CanExecuteChanged(this, EventArgs.Empty);

    }

 

    publiceventEventHandlerCanExecuteChanged = delegate { };

}

The view model implements property change notification. Because all of the target frameworks support the latest .NET features, I can use the CallerMemberName attribute to infer the property name when I raise the property change event:

protectedvirtualvoidOnPropertyChangedImplicit([CallerMemberName] string propertyName =null)

{

    OnPropertyChanged(propertyName);

}

 

protectedvirtualvoidOnPropertyChanged(stringpropertyName = null)

{

    PropertyChanged(this, newPropertyChangedEventArgs(propertyName));

}

The implementation of a property looks like this:

privatestring _exceptionMessage;

 

publicstring ExceptionMessage

{

    get { return _exceptionMessage; }

    set { SetProperty(ref _exceptionMessage, value); }

}

The command I defined earlier can be wired to fetch the URL (but only if it is valid):

SubmitCommand = newActionCommand(

    obj => FetchUrl(),

    obj => IsValid());

privatebool IsValid()

{

    ExceptionMessage = string.Empty;

 

    if (Uri.TryCreate(Url, UriKind.Absolute, out _uri))

    {

        returntrue;

    }

 

    ExceptionMessage = "The URL entered is invalid.";

    returnfalse;

}

If it is valid, the command executes and fetches the content of the URL or traps the exception:

privateasyncvoid FetchUrl()

{

    ExceptionMessage = string.Empty;

    Content = "Loading...";

 

    try

    {

        varwebClient = WebRequest.CreateHttp(_url);

               

        var task = Task<WebResponse>.Factory.FromAsync(

            webClient.BeginGetResponse,

            webClient.EndGetResponse,

            null

            );

               

   var response = await task;

 

        using (var stream = response.GetResponseStream())

        {

            var encoding = Encoding.GetEncoding("utf-8");

            using(var reader = newStreamReader(stream, encoding))

            {

                Content = HtmlStrip(await reader.ReadToEndAsync());

                Url = string.Empty;

            }

        }

    }

    catch(Exception ex)

    {

        Content = string.Empty;

        ExceptionMessage = ex.Message;

    }

}

Notice that the implementation uses advanced features, such as converting the Asynchronous Program Model (APM) signature of the web client to a Task so that the new async and awaitkeywords can be used. Finally, the content of the URL is stripped of tags and white space:

privatestaticstringRemoveHtml(string input)

{

    input = Regex.Replace(input, "<style.*>(.|\n)*?</style>", string.Empty);

    input = Regex.Replace(input, "<script.*>(.|\n)*?</script>", string.Empty);

    input = Regex.Replace(input, @"<xml.*>(.|\n)*?</xml>", string.Empty);

    input = Regex.Replace(input, @"<(.|\n)*?>", string.Empty);

    returnRegex.Replace(input, @"^\s*$\n", string.Empty, RegexOptions.Multiline);

}

Let’s take a step back. I’ve just defined not only important domain data (the URL to fetch, error information, and content) but business logic (such as the validation of the URL) and an implementation of the networking stack … all in a single assembly! This special portable assembly is shareable between the target frameworks “as is” without having to recompile it. That’s quite powerful! In fact, because all of the logic is self-contained in the assembly, these are the only steps I need to build a Windows Store app using the logic:

1. Create a new Windows Store app (I used the“Blank” template)

2. Reference the PCL

3. Update the XAML in the main page to reflect the application

That’s it! Just three steps. I instantiate the view model in the XAML, like this:

<GridBackground="{StaticResourceApplicationPageBackgroundThemeBrush}">

    <Grid.DataContext>

        <CommonLibrary:ViewModel/>

    </Grid.DataContext>

    <Grid.RowDefinitions>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="Auto"/>

        <RowDefinition Height="*"/>

    </Grid.RowDefinitions>

    <StackPanel Margin="5"Grid.Row="0" Orientation="Horizontal">

        <TextBlockText="URL: "VerticalAlignment="Center"/>

        <TextBlock Margin="5 0 0 0"/>

        <TextBoxText="{BindingUrl,Mode=TwoWay}"Width="400"/>

        <TextBlock Margin="5 0 0 0"/>

        <ButtonCommand="{BindingSubmitCommand}"Content="Fetch"/>

    </StackPanel>

    <TextBlock Grid.Row="1"Margin="5"Text="{Binding ExceptionMessage}"Foreground="Red"/>

    <ScrollViewer Grid.Row="2"Margin="5">

    <TextBoxIsReadOnly="True"Text="{BindingContent}"

                TextWrapping="Wrap"/>

    </ScrollViewer>

</Grid>

The view model actually fires in the designer, so we can see a sample error message and the button disabled because a valid URL is not entered.

 

Compile, deploy, and run the application and enter a sample URL, such as my blog, https://csharperimage.jeremylikness.com/and click the Fetch button. The result is shown below. Note this is without having to write a single line of code in the Windows Store app:

 

Next, I created a Windows Phone 8 project. I started by adding the reference like I did with the Windows Store app. Then I pasted the exact same XAML and modified it to put the button on its own row so it fit the phone screen better. That’s it. No code behind – just wire the XAML and run it. This is the result:

 

Obviously this is a contrived example but it should illustrate the power of what is possible using the PCL. The source code for this blog post is available from:

https://bit.ly/UwbPOh

For more examples, I created a fairly comprehensive example using blog feeds that has a code-based shared between a WPF desktop app and a Windows Store app. You can download that source code from:

https://windows8applications.codeplex.com/

From this post you’ve learned a technique to share code between Windows 8 and Windows Phone 8 applications using the Portable Class Library. Remember, the library allows you to specify your target framework so it is possible to combine code with Silverlight, WPF, or older Windows Phone 7.x applications as well. Keeping your common code in platform-agnostic assemblies makes it possible to reuse a large portion of your code base and allows you to write and run unit tests in one place instead of several. I hope you have fun building some great new apps for Windows 8 and Windows Phone 8!

 

About the author

Jeremy-Likness2

Jeremy Likness is a principal consultant at Wintellect, LLC. He has worked with enterprise applications for more than 20 years, 15 of those focused on web-based applications using the Microsoft stack. He is a three-year Microsoft MVP and was awarded MVP of the Year in 2010. Jeremy is the author of Building Windows 8 Apps with C# and XAML (Addison-Wesley) and regularly speaks and blogs. You can learn more about his book online at https://bit.ly/win8design and follow his blog at https://csharperimage.jeremylikness.com/.   Follow him on Twitter

About MVP Mondays

The MVP Monday Series is created by Melissa Travers. In this series we work to provide readers with a guest post from an MVP every Monday. Melissa is a Community Program Manager, formerly known as MVP Lead, for Messaging and Collaboration (Exchange, Lync, Office 365 and SharePoint) and Microsoft Dynamics in the US. She began her career at Microsoft as an Exchange Support Engineer and has been working with the technical community in some capacity for almost a decade. In her spare time she enjoys going to the gym, shopping for handbags, watching period and fantasy dramas, and spending time with her children and miniature Dachshund. Melissa lives in North Carolina and works out of the Microsoft Charlotte office.