Question

Upon running the following code, in a project from F# WPF template, to which is added the Nuget Prism

module MainApp

open System
open System.Windows
open System.Windows.Controls
open Microsoft.Practices.Unity
open Microsoft.Practices.Prism.UnityExtensions;
open FSharpx

type Shell = XAML<"MainWindow.xaml">

type App () =
   inherit Application()

   override x.OnStartup e =
      base.OnStartup(e);
      let bt = new BootStrapper()
      bt.Run()

and  BootStrapper () = 
   inherit UnityBootstrapper()

   override x.CreateShell() = 
     let a = x.Container.Resolve<Shell>()

     let b = a.Root
     b :> DependencyObject

   override x.InitializeShell()= 
         base.InitializeShell();
         App.Current.MainWindow <- x.Shell :?> Window
         App.Current.MainWindow.Show()


[<STAThread>]
(new App()).Run() |> ignore

I get no error at compile time, but at runtime an exception says that a.Root is a FrameworkElement, which can not be casted to a Window.

Upon debugging, I see that the runtime content of 'a' is of same type than the internal representation of the XAML Type provider, a {FSharpx.TypeProviders.XamlProvider.XamlFile}, as in here, and its internal dictionary is empty.

I am not sure the internal representation of the TP is supposed to surface out. It looks as if the Type Provider mechanic is ignored by Unity. I suppose it is because Unity seems to work with reflection to figure out dependencies.

Has anyone experienced a similar behaviour using TP that could shed some light ?

PS :This discrepency compile/runtime in F# is quite suprising. Although there must be a good reason for it I had forgotten the possibility of such occurences !

Was it helpful?

Solution

As I see in FSharpX source code, Xaml type provider is erased one - you don't have Shell type as is in metadata, everything that works with this type is erased to operations with base type - XamlFile. So this

let a = x.Container.Resolve<Shell>()

will be erased to smth like

let a = x.Container.Resolve<XamlFile>()

so Unity will just create fresh instance of XamlFile. In contrast, if you try to instantiate Shell directly - then F# compiler will use provided constructors so this

let a = Shell()

will effectively mean

let a = XamlFile(XamlReader.Parse( <content-of-xaml-file> ))

In your case you can probably instantiate Shell and then use x.Container.BuildUp() to populate its internals.

type App () =
   inherit Application()

   override x.OnStartup e =
      base.OnStartup(e);
      let bt = new BootStrapper()
      bt.Run()

and  BootStrapper () = 
   inherit UnityBootstrapper()

   override x.CreateShell() = 
     let a = Shell()
     x.Container.BuildUp(a.Root) :> _

   override x.InitializeShell()= 
         base.InitializeShell();
         App.Current.MainWindow <- x.Shell :?> Window
         App.Current.MainWindow.Show()


[<STAThread>]
(new App()).Run() |> ignore
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top