Freigeben über


F# + WPF + Events

I recently had to do some travelling for the VS launch event in Las Vegas and QCON event in Beijing. One of the things thats nice about travelling is that it gives you time to do some things you may not otherwise do - in my case, I had a chance to try to (re) learn WPF and see how I can use F# with WPF. This sample is a result of that.

This sample builds on the F# Twitter streaming sample that Don blogged about. Our goal will be to take the sample and modify it to build a WPF UI on top of the twitter event stream so that we can visualize the tweets.

Download the twitter streaming client sample .

Strategy

The overall implementation strategy is to implement an event handler for the twitter events and push updates into an observable collection, which is a WPF collection that can be data-bound to a UI control. XAML data binding is used to hook up the elements of the collection to the list box items.

Details

To start off, we have code loads the XAML file (which was compiled as a resource into the F# application) and then finds the controls we are interested in:

Loading XAML into F#

let w = Application.LoadComponent(new System.Uri("/twitterstream;component/Window.xaml", System.UriKind.Relative)) :?> Window
let b = w.FindName("buttonToggle") :?> Button
let imageList = w.FindName("imageList") :?> ListBox

Next, we create an observable collection, bind it to the image list, and pass that to a function which sets up the event handler:

ObservableCollection

let c = new ObservableCollection<UserStatus>()
imageList.ItemsSource <- c
setupEvent c

Here’s how we setup the event handler:

Event Composition

let setupEvent (c : ObservableCollection<UserStatus>) =
    twitterStream.NewTweet
    |> every 20
    |> Event.choose parseTweet
    |> Event.add (fun s ->
                    System.Diagnostics.Debug.WriteLine(s.Status)
                    c.Insert(0, s) |> ignore)

Notice that the event handler will eventually insert the parsed tweet into the observable collection. (If you are not familiar with events in F#, I will post a blog entry on this in the near future).

The parseTweet function takes the XML and returns UseStatus type:

Code Snippet

type UserStatus =
    { UserName : string;
      ProfileImage : string;
      Status : string;
      StatusDate : DateTime }

Once we data bind the “root” object via F# code, the XAML code takes care of binding elements of the observable collection (which have type UserStatus). Here’s the interesting XAML code in the data template for the ListBox that binds the elements of the collection to the list box items:

XAML

<Image Grid.Column="0"
       Source="{Binding Path=ProfileImage}"
       Stretch="Fill"
       Height="50" />
<Label Grid.Column="1"
       Height="50">
    <TextBlock Text="{Binding Path=Status}"
               TextWrapping="WrapWithOverflow"
   />
</Label>

Notice that the image is bound to the URL specified in the ProfileImage field of the UserStatus type, and the Label content is bound to the Status field of the UserStatus type.

Summary

I hope this sample highlights how to integrate F# and F# events with WPF.