WPFEventLoop in FSharp V4 with fsi.exe and WPF V4
While checking a compiled F# program to make sure it would execute in FSI (FSharp Interactive), I found that over 2000 lines of code had no errors or messages but 1 line of code referencing 'SelectionBrush' produced a 'not defined' error. After changing the '#I' and '#r' directives several times without effect, I decided I would paste the code into the F# REPL Window. Here is an abbreviated portion of the output:
----------------------------------------
val Create : unit -> Compiler.Interactive.IEventLoop
val Install : unit -> unit
end
--> Added 'C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0' to the library include path
--> Referenced 'c:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\presentationcore.dl
--> Referenced 'c:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\presentationframework.dll'
--> Referenced 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.dll'
--> Referenced 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\System.Core.dll'
--> Referenced 'c:\Program Files\Reference Assemblies\Microsoft\Framework\v3.0\WindowsBase.dll'
--> Referenced 'C:\Users\OWNER\SharpDevelop Projects\the Explorer Imperative\the Explorer Imperative\bin\Debug\Interop.IWshRuntimeLibrary.dll'
textBox1.SelectionBrush <- Brushes.Black
---------^^^^^^^^^^^^^^
stdin(240,10): error FS0039: The field, constructor or member 'SelectionBrush' is not defined
>
---------------------------------------
Notice the 'Create' and 'Install' of the EventLoop. This is followed by the information that v4.0 was added to the Linrary Include path. This was followed by the information that it was still referencing v3.0 libraries.
Since this information was not output for the WPFEventLoop I deduced that loaded files did not produce that information so I pasted the code for the EventLoop into the REPL and sure enough, the Include Libraries were v3.0 (period->).
I did a quick check by commenting out the '#load' statement for the EventLoop and pasting the 2000 plus lines of code into the REPL. It compiled without errors but no WPF Event Loop. This meant that the only events the program could respond to were the events I had programmedevent handlers for(no typing).
The problem of WPF v4.0 Features not being defined in mysterious circumstances should not normally occur if you have the correct includes and referencesbut in this case the problem was hidden by the EventLoop being loaded from a separate file.
The Quick and Easy (and not even dirty) solution is to replace the v3.0include path with the v4.0 include path. On my computer it is this:
#I @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
The first two lines are the original ones the last 2 are the new ones, of which only the first is required by the Event Loop but are probably required by something else in WPF v4.0.. The code below is the property of Microsoft Corporation and is included here to show the proper placement of the v4 include directive.
#light
#if INTERACTIVE
#I @"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0"
#r "presentationcore.dll";;
#r "presentationframework.dll";;
#r "WindowsBase.dll";;
module WPFEventLoop =
open System
open System.Windows
open System.Windows.Threading
open Microsoft.FSharp.Compiler.Interactive
open Microsoft.FSharp.Compiler.Interactive.Settings
type RunDelegate<'b> = delegate of unit -> 'b
let Create() =
let app =
try
let app = new Application() in
new Window() |> ignore;
app
with :? InvalidOperationException -> Application.Current
let disp = app.Dispatcher
let restart = ref false
{ new IEventLoop with
member x.Run() =
app.Run() |> ignore
!restart
member x.Invoke(f) =
try disp.Invoke(DispatcherPriority.Send,new RunDelegate<_>(fun () -> box(f ()))) |> unbox
with e -> eprintf "\n\n ERROR: %O\n" e; reraise()
member x.ScheduleRestart() = ()
}
let Install() = fsi.EventLoop <- Create()
WPFEventLoop.Install();;
#endif
Keep your mind open, your mouth shut, and your computations closed!