Dogs Chasing Squirrels

A software development blog

Tag Archives: WPF

Akka.NET, Prism, Unity, and WPF

10

Since I’ve been reading up on Reactive Extensions, I listened with interest to the recent .NET Rocks! podcast on the subject. During the conversation, Akka.NET was mentioned.

Akka.NET is another reactive technology. It’s an implementation of the Actor model. Basically, you break down an application’s functionality into small computational units called Actors which have limited state and communicate via message passing. There are parallels in Rx’s concept of observables and observers. Akka.NET also provides the kind of supervision hierarchy that you find in erlang, which is that an actor has child actors and when those child actors fail, the parent can resume or restart the failed children. This makes the application ‘self healing’.

I watched two Pluralsight course on Akka.NET by Jason Roberts, Building Concurrent Applications with the Actor Model in Akka.NET and Building Reactive Concurrent WPF Applications with Akka.NET (subscriptions required for both links). The former gives an overview of Akka.NET and the latter applies it to an MVVM WPF application.

In the demo MVVM application, the author uses Akka.NET with Ninject dependency injection and the MVVM Light toolkit. Personally, I prefer Unity and Prism, so as an exercise for myself I created the demo using those two languages. The result is on GitHub at https://github.com/mkb137/AkkaPrismUnityDemo.

The project consists of
* Akka.DI.Unity – A copy of Akka.NET’s Akka.DI.Unity upgraded from Unity 3.5 to Unity 4.0. No code changes were required otherwise.
* AkkaPrismUnityDemo – The Prism shell project
* AkkaPrismUnityDemo.Infrastructure – The common infrastructure project (which in this simple demo only contains the region names)
* AkkaPrismUnityDemo.Modules.Stocks – The main module containing the demo code.

A screenshot of the result is shown at the top of this post. In it, the view model creates actors which then have knowledge of the view model that created them and will call methods on the view model when messages are received and processed.

Here a view model creates an actor and passes it a reference to itself:

this.StockToggleButtonActorRef = 
    this.UnityContainer.Resolve<ActorSystem>()
    .ActorOf( 
        Props.Create( () => new StockToggleButtonActor( 
            this.StocksCoordinatorActorRef, 
            this, 
            this.StockSymbol
        ) 
    ) 
);

Here the actor makes a callback to the view model:

this.Receive<ToggleStockMessage>( message => {
    this._stocksCoordinatorActorRef.Tell( new WatchStockMessage( this._stockSymbol ) );
    this._viewModel.UpdateButtonTextToOn();
    this.Become( this.ToggledOn );
} );

Like Rx and its Observables/Observers, messages are handled on the thread pool so actors will make full use of the processors available on the machine with no extra effort from the developer.

It’s an interesting technology. Compared to Rx, Akka is missing some of Rx’s advanced publish/subscribe methods like the ability to buffer or throttle messages. It does have a Sample equivalent via the scheduler’s ScheduleTellRepeatedly method. On the plus side, it provides the supervision hierarchy and provides a more natural message pipeline. With Rx it seems like having an object that is both observer and observable (i.e. is part of a pipeline), while supported, is somehow discouraged.

F#, WPF, and Prism

0

I recently attempted to use F# to create a WPF project using the Prism MVVM library.  The project, if you want to download it or look at the code, is at https://github.com/mkb137/FSharpAndPrism.

Creating a WPF Application in F#

This isn’t too hard.  There’s no option to create an F# WPF application by default, but if you create an F# Console Application and then, in the project settings, flip it over to “Windows Application” it will run like one.

To get the WPF libraries, you have to add these references:
* PresentationCore
* PresentationFramework
* UIAutomationClient
* UIAutomationTypes
* WindowsBase
* System.Xaml

I used the FsXaml project to create usable F# types from WPF XAML files.
You can add vanilla XAML files, like App.xaml, with no backing class and then convert them to F# types via:

type App = XAML<"App.xaml", true>

Two things to be aware of:
1. All XAML files must be compiled as “Resource” (the default is None)
2. Visual Studio LIES.  As you may know, in F# the order of the files in solutions matter.  In F# projects, Visual Studio gives you “move up” and “move down” functions to put the files in order.  But once you start adding XAML files, all bets are off.  If you find the solution mysteriously failing to find libraries that it should, open your .fsproj file in a text editor and have a look at the included file order.  You may need to order it manually.

Adding Prism

I used the UnityBootstrapper, which in F# looks like this:

type Bootstrapper() =
    inherit UnityBootstrapper()
    override this.CreateShell() = 
        WindowUtils.loadComponent "/FSharpAndPrism;component/Shell.xaml"
    override this.InitializeShell() =
        base.InitializeShell()
        Application.Current.MainWindow <- ( this.Shell :?> Window )
        Application.Current.MainWindow.Show()
    override this.ConfigureContainer() =
        base.ConfigureContainer()
        this.Container.LoadConfiguration() |> ignore
        this.Container.RegisterInstance( this.Container ) |> ignore
    override this.ConfigureModuleCatalog() =
        base.ConfigureModuleCatalog()
        let moduleCatalog = this.ModuleCatalog :?> ModuleCatalog
        moduleCatalog.AddModule typedefof<AlphaModule> |> ignore

That WindowUtils.loadComponent is just a utility function to load the XAML resource:

module WindowUtils =
    let loadComponent( path ) =
    let resourceLocator = new Uri( path, UriKind.Relative )
    Application.LoadComponent( resourceLocator ) :?> DependencyObject

So I create a Shell with a MainRegion region…

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:prism="http://www.codeplex.com/prism"
    xmlns:infrastructure="clr-namespace:FSharpAndPrism.Infrastructure;assembly=FSharpAndPrism.Infrastructure"
    Title="F# Prism Demo" Height="150" Width="500"
    WindowStartupLocation="CenterScreen"
    >
    <StackPanel Orientation="Vertical">
        <Label Content="View Goes Here:"/>
        <ContentControl prism:RegionManager.RegionName="{x:Static infrastructure:RegionNames.MainRegion}"/>
    </StackPanel>
</Window>

And I create a view…

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Background="White"
    >
    <StackPanel Orientation="Horizontal">
        <Label>This is my view - Data context = </Label>
        <Label Content="{Binding}"/>
    </StackPanel>
</UserControl>

Register it as an F# type…

type MyView = XAML<"MyView.xaml",true>

And define a module that registers it with the region:

type AlphaModule( regionManager : IRegionManager, container : IUnityContainer ) =
    interface IModule with
        member this.Initialize() =
            regionManager.RegisterViewWithRegion( RegionNames.MainRegion, typedefof<MyView> ) |> ignore

And the result is… It doesn’t work.  The application runs but my view is not being loaded into the region.  Why?  Actually, with a little digging I find that the view is being loaded, it’s just not rendering.

FSharpAndPrism-Failure

FsXaml, Prism, and Unity

Problem #1 – Extra Constructor

As it turns out, when FsXaml creates a type derived from UserControl, in addition to UserControl’s void UserControl() constructor, FsXaml is adding a hidden void UserControl(FrameworkElement) constructor.  If the default configuration is not overridden, Unity will use this constructor when resolving the component and the type created with this constructor will not render itself correctly.  A simple but tedious way around this problem is to, for each view, register it with Unity so that the constructor taking no parameters is used.

container.RegisterType<MyView>( new InjectionConstructor() ) |> ignore

FSharpAndPrism-NoContext

Problem #2 – Adding a data context

Prism Views aren’t that useful with out their ViewModel data contexts and those are usually passed in the constructor.  So the first thing we want to do is subclass our the type that FsXaml created and add our own constructor.  This, by the way, solves our Unity problem as well since our subclassed type won’t have the bogus constructor that FsXaml is creating.
Here’s a basic view model type:

type MyViewModel() =
    let mutable name: string = null
    member this.Name
        with public get() = name
        and public set value = name <- value

Here’s our subclassed view (where the original has been renamed with a tick):

type MyView' = XAML<"MyView.xaml",true>

type MyView() =
    inherit MyView'()
    new( viewModel : MyViewModel ) as this =
        MyView()
        then
            this.DataContext <- viewModel

and… we have a problem.  By default, FsXaml derived types are sealed.  There’s no real reason for this other than that FsXaml is using a type provider from the fsprojects/FSharp.TypeProviders.StarterPack and it creates types as sealed for, I suppose, educational purposes.  If the “Sealed” attribute is removed from the created type it works fine.  I submitted a pull request to FsXaml who asked me to submit it upstream to FSharp.TypeProviders.StarterPack.  I submitted it a moment ago and haven’t heard back yet.  Until then, a “fixed” FsXaml implementation is at mkb137/FsXaml

Using the modified FsXaml library, it works and we have our view loaded with its data context:

FSharpAndPrism-WithDataContext

Final Problem: FSC: error FS2024: Static linking may not use assembly that targets different profile.

A normal WPF project is compiled against the .NET 4.5 profile which is known internally as Profile7 (see a list of PCL profiles here.  If you attempt to directly use any third-party library that is compiled not just for .NET 4.5, but for .NET 4.5 and Windows Phone (e.g. Profile78), you’ll get the error that you would never see in the same C# project:

FSC: error FS2024: Static linking may not use assembly that targets different profile.

And there’s no way around it as far as I know.  The bug has been logged here on F#’s current home on GitHub, and not yet fixed.