clojure-clr - getting started on Windows WPF

369 views
Skip to first unread message

kjeldahl

unread,
Apr 1, 2011, 6:54:13 AM4/1/11
to Clojure
I'm toying around with clojure-clr, and it seems to work great. But
getting started is a bit challenging to say the least (which may very
well be because of me beeing rookie with .net/clr as well). Anyway,
I've managed to find an example using the Windows Forms API, a simple
hello world example:

(import '(System.Reflection Assembly))
(Assembly/LoadWithPartialName "System.Windows.Forms")
(ns helloworld
(:import (System.Windows.Forms MessageBox)))
(MessageBox/Show "Hello world")

Runs fine under the latest 1.3 build of clojure-clr at least.

But I have yet to find any examples or get anything working using the
WPF APIs instead, which seems to be the direction Windows is heading.
Most WPF examples assumes using Visual Studio with it's GUI builder
and/or XML files. It is possible to do programmatically as well, so in
theory it should work fine with clojure. Most minimal examples of
programmatic WPF applications in C# just creates and shows a Window.
But when I try to do similar stuff in clojure-clr, there seems to be
some plumbing needed.

I haven't figured it all out yet, but it seem necessary to set up the
proper threading environment (SPF thread for GUI or something like
it), and try to create a window from that thread.

Needless to say, I'm struggling a bit and though I would ask this
community if anybody had a working example or links to such, for
starting out with clojure-clr and WPF.

Thanks,

Marius K.

kjeldahl

unread,
Apr 13, 2011, 7:48:39 AM4/13/11
to Clojure
Following up on my own subject, I've created an updated gist to run on
recent builds of clojure-clr (1.3.0-master-SNAPSHOT) based on another
gist I found.

It's not the prettiest of code I've found, but I guess CLR's
abstractions and threading models can be blamed for a lot of it.
What's more annoying though is that while the gist below runs fine
when pasted into a running repl, it only does so the first time. Close
the window and paste it once more, and nothing appears.

There may be an issue with the CLR AppDomain model only allowing one
instance of an Application object or similar (based on messages I've
encountered while exploring), but I don't really know and I haven't
managed to get everything to completely "unload" so that the code
would work when invoked repeatedly within a running repl.

If anybody knows how this can be fixed (without restarting the repl
environment), please chime in. I like the statelessness offered by
clojure and a running repl, but the code as it currently exist doesn't
really support this model.

The updated gist can be found here:

https://gist.github.com/917391

Thanks,

Marius K.

dmiller

unread,
Apr 13, 2011, 11:52:08 PM4/13/11
to Clojure
Reloading will definitely cause a problem.

According to MS docs:

"Only one instance of the Application class can be created per
AppDomain, to ensure shared access to a single set of application-
scope window, property, and resource data. Consequently, the default
constructor of the Application class detects whether the instance
being initialized is the first instance in an AppDomain; if it is not,
an InvalidOperationException is thrown.

"The Application object for the current AppDomain is exposed from the
static Current property."

Thus:


(import 'System.Reflection.Assembly)
(Assembly/LoadWithPartialName "PresentationFramework")
(import 'System.Windows.Application)


Application/Current ;=> nil
(Application.) ;=> #<Application
System.Windows.Application>
Application/Current ;=> #<Application System.Windows.Application>
(Application.)
InvalidOperationException Cannot create more than one
System.Windows.Application instance in the same AppDomain.
System.Windows.Application..ctor (:0)


I don't know why you'd need the app atom since you can just use
Application/Current. Similarly, you could check Application/Current
before doing (Application.)

I suppose if you really wanted to get fancy, you could create the WPF
application in other AppDomain and then wipe it. Not sure why.

NB: I've not done any WPF work, just working from general principles.

-David


On Apr 13, 6:48 am, kjeldahl <mariusauto-googlegro...@kjeldahl.net>
wrote:

Marius Kjeldahl

unread,
Apr 14, 2011, 3:04:55 AM4/14/11
to clo...@googlegroups.com
On 04/14/2011 05:52 AM, dmiller wrote:
> Reloading will definitely cause a problem.
> ...

> I don't know why you'd need the app atom since you can just use
> Application/Current. Similarly, you could check Application/Current
> before doing (Application.)

In theory, that all sounds easy, but I haven't managed to pull it off.
That may very well be due to the challenge of juggling threads and
dispatchers, and other .Net specific abstractions I've only scratched
the surface off yet.

I replaced the app atom with code that creates an instance of
Application only when needed (reusing Application/Current instead when
not needed), but it still does not work. Maybe there's stuff I need to
do to the threads and dispatchers as well.

Thanks anyway,

Marius K.

Marius Kjeldahl

unread,
Apr 14, 2011, 8:31:35 AM4/14/11
to clo...@googlegroups.com
FWIW, I did a small writeup of my first encounter with clojure-clr at:

http://kjeldahl.net/d7/clojure-clr-first-encounter

Thanks,

Marius K.

Reply all
Reply to author
Forward
0 new messages