I've been using the OO approach to define WinForms and user controls, mainly because it's more intuitive for me.

That said, until there are forms designers for F#, I prefer to design forms in C# and just use F# for lower level calculations where functional programming gets real elegant.

By on 11/20/2008 5:17 AM ()

I tend to prefer the functional/scripting way, but then the UIs I've been creating that way tend to be quite lightweight, only having a few controls. In this case wiring up your controls functions works well inside a function.

I although winforms use inheritance internally a lot I don't think you really need to use inheritance to use them, I rarely want to inherit from a control to change it's functionality.

The exception to this is you may want to create several different types of form. I think the OO style may work better when you have lots of controls and want to reuse the form's a lot, and have several different types of forms. The advantage I see here is that you can use the OO style to expose a friendly interface to your form rather than forcing the user to work directly with the controls.

Cheers,

Rob

By on 11/20/2008 2:23 AM ()

I'm struggling to find a stateless way to capture mouse clicks. For example, my application is like a Paint program... the user clicks and holds the mouse, drags across the screen, and then releases. The result is that a line is drawn from the first point to the second point.

I'm not sure what to do other than capture the first click in a "ref Point" value and read & reset the ref Point when the mouse button is released.

Any recommendations?

By on 11/20/2008 9:45 AM ()

I'm struggling to find a stateless way to capture mouse clicks. For example, my application is like a Paint program... the user clicks and holds the mouse, drags across the screen, and then releases. The result is that a line is drawn from the first point to the second point.

I'm not sure what to do other than capture the first click in a "ref Point" value and read & reset the ref Point when the mouse button is released.

Any recommendations?

I'm curious to see if someone else comes up with a more elegant solution to this, but what about something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
open System;
open System.Windows.Forms;
open System.Drawing;

let DrawLine (a:Point) (b:Point) = 
    () //Code here to draw a line

let MyMouseDown (form:Form) (down_arg:MouseEventArgs)
    let MyMouseUp (up_arg:MouseEventArgs) = 
        DrawLine down_arg.Location up_arg.Location
    form.MouseUp.Add MyMouseUp
    ()

let x = new Form()
x.MouseDown.Add (x |> MyMouseDown)

the only problem with this code is that the handler that gets added via form.MouseUp.Add MyMouseUp never gets removed, so obviously this is going to be a problem. I think you can get around this limitation using IDelegateEvent.AddHandler instead of IEvent.Add, but I'm having trouble figuring out the syntax to get that to work.

There may be other issues with this approach as well, not sure yet.

By on 11/20/2008 2:25 PM ()

@divisortheory I thought about this... basically I would add a mouse up listener within the mouse down that waits for the end of the user's click... then if would remove itself once it's run. I'll try this and let you know how it went, but I'm about to leave for holiday so don't hold your breath waiting ;)

By on 11/21/2008 5:17 AM ()

I'm starting to dislike this method more and more. Don Syme had a post addressing a similar issue on his blog a while back. Basically it boiled down to that he did keep a state variable, but it was hidden from inaccessible to anything except for the event in question.

[link:blogs.msdn.com]

The code he used was this:

1
2
3
4
5
6
7
8
9
10
11
12
13
let mkMouseTracker (c : #Control) =
    let fire,event = IEvent.create() in
    let lastArgs = ref None in
    c.MouseDown.Add(fun args -> lastArgs := Some args);
    c.MouseUp  .Add(fun args -> lastArgs := None);
    c.MouseMove.Add(fun args ->
        match !lastArgs with
        | Some last -> fire(last,args); lastArgs := Some args
        | None -> ()); 
    event

let mouseEvent = mkMouseTracker form
do mouseEvent.Add(fun (args1,args2) -> move view args1 args2)

Modifying this to create a down/up combined event could be done like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
let handleDownUp down up = 
   MessageBox.Show(String.Format("Down at {0}, Up at {1}", down, up))

let mkDownUpEvent : (c : #Control) = 
   let fire, event = Event.create()
   let downargs:MouseEventArgs ref = ref null
   c.MouseDown.Add(fun args -> downargs : args);
   c.MouseUp.Add(fun args -> fire(!downargs, args));
   event

let form = new Form()
mkDownUpEvent form
   |> Event.listen(fun (down, up) -> PrintStuff down.Location up.Location)

There may be a way to do it more statelessly, but the more I think about it, the more I think you should just use state, but hide the state as much as possible

By on 11/21/2008 5:45 AM ()

@PetroNerd: how do you create a form in C# and use it in F#?

By on 11/20/2008 1:39 PM ()

@PetroNerd: how do you create a form in C# and use it in F#?

Actually I usually do the opposite, as shown here, towards the end of the article. But the same thing should be doable in reverse. Basically create the form(s) in C# and compile to a library (*.dll). Then from F#, use them.

BTW, there's also some code that captures the mouse location in that article, although it doesn't do exactly what they're talking about in this thread.

What I'd really love to be able to do is to mix and match things. For example, write a form in C# and all of the math stuff in F#, compile each with the appropriate compiler, then link them into a single .exe file without having to use dll's.

Or maybe there's already a way to do that and I haven't discovered it yet. I'm still playing and learning, since I won't really be doing much serious F# development until F# becomes fully supported and accepted in general by my customers.

By on 11/21/2008 7:05 AM ()

Cyclic dependencies between F# and C# within a single project would make compiling both sources in a single project tricky.

If the dependencies are one way (C# to F#), then you might be able to run the fsc.exe first and csc.exe (is that the C# compiler?) second, leaving your project fully built.

The way the Groovy language handles cyclic dependencies between languages is to have a joint compiler... the compiler phase 1 runs through all the Groovy code and generates object file stubs so that the next phase has something to link against. The 2nd phase compiles the java code against the groovy stubs, linking correctly. The 3rd phase then recompiles the Groovy object files linking correctly against the classes compiled in Phase 2.

The problem with this is what to do when you want to have cyclic dependencies between F#, C# and Boo. And there's also an issue with large C# projects with a little F# code... you'd have to change the compiler for all the C# code to this new F# joint compiler which probably triggers regressions testing. (Those were our two issues anyway).

My group decided to settle on a core language and define an extension language (Core=Java, extension=Groovy). And then only allow unidirectional dependencies from core to extension. With dependency injection frameworks like Spring, we can easily hide dependencies behind interfaces and everything works well. I'd recommend that.

By on 11/21/2008 7:31 AM ()
IntelliFactory Offices Copyright (c) 2011-2012 IntelliFactory. All rights reserved.
Home | Products | Consulting | Trainings | Blogs | Jobs | Contact Us | Terms of Use | Privacy Policy | Cookie Policy
Built with WebSharper