Skip to content

net

Observable event subscription

The other day I was trying to create an explicit interface implementation of an event and ran into a snag. Now I've done many explicit interface implementations before, but, I guess, never of an event, because I'd not seen the below compiler error before:

An explicit interface implementation of an event must use property syntax

Huh? I did some searches on that error and the best reference was this page. I had long forgotten that the whole += and -= was closely related to how properties work. But instead of using get and set you can create your own logic for subscribe and unsubscribe using add and remove.

As Oliver points out on his blog, it does mean that your event just becomes a facade and you still need another event that actually is being subscribed to. So for that explicit interface implemenation you'd get something like this:

interface IFoo
{
   event EventHandler FooHappened;
}

class SomeClass : IFoo 
{
  private event EventHandler internal_FooHappened;

  public event EventHandler IFoo.FooHappened
  {
    add { internal_FooHappened += value; }
    remove { internal_FooHappened -= value; }
  }

  private void OnFooHappened()
  {
    if( internal_FooHappened != null )
    {
      internal_FooHappened(this,EventArgs.Empty);
    }
  }
}

Now this is really an edge case, imho. But the same syntactic trick does allow for something else that's pretty cool, i.e. being able to be notified when someone subscribes to your event. I've had it happen a number of times, where it would have been useful to take some action on subscription. Maybe the event needs some extra resource, that you don't want to initialize unless someone needs it. It may even be that the real event handler is that resource. So now you can use the above syntax and put extra logic inside of the add to initialize that resource, like this:

class SomeClass
{
  SomeResource myResource;

  public event EventHandler FooHappened
  {
    add
    {
      if( myResource == null )
      {
         myResource = new SomeResource();
      }
      myResource.FooHappened += value;
    }
    remove
    {
      myResource.FooHappened -= value;
      if( myResource.FooHappened == null )
      {
         myResource.Dispose();
         myResource = null;
       }
    }
  }
}

LFSLib.NET 0.15b released

Although 0.15b was supposed to be the version that brings LFS proxy support to LFSLib.NET, a crash-bug with AXI & AXO packets forced me to rollback that incomplete code for now and release a bugfix version.

The bugs fixed in this version are:

  • AXI & AXO packets were not properly received and killed the TCP handler
  • Eliminated race condition in static population of encodings
  • Fixed bug with text-less button
  • Socket clean-up in UDP handling could throw unexpected exceptions
  • OutSim & OutGauge used bad buffer sizes if ID was 0 and would throw an OutOfRangeException
  • Close() could throw NotConnected exception, which was useless

The remainder of the changes are clean-up and non-breaking, forcing some more parts of the API into obsolescence.

Full details are in the release notes.

All links, docs, etc are at lfs.fullmotionracing.com

Playing with Xaml and LFS

I thought it was about time to see how hard it would be to get Live For Speed Track Maps into Xaml for use on the desktop or Silverlight. I initially started with the LFS's SMX (simple mesh format) files, but taking triangle data and turning it into a manageable number of polygons for vector representation is proving to be an interesting exercise. I might get back to it later, but for now, have found a more productive approach.

LFS provides a file format called PTH which basically contains the drive line in world coordinates as a set of nodes for each track configuration. But here's cool part: Every node also includes orientation and the left and right distances from the node to the track edges and drivable area edges. Given the left and right edges from two nodes describes a rectangle. I decided to render this out as a series of polygons in Xaml and the results was a very usable representation of the track.

But this still generates a lot of polygons for such a relatively simple shape. I initially went down the path of just skipping over nodes and doing a reduction of detail that way. This approach, however, quickly deteriorated the detail significantly. My next approach was to take the edges of multiple node polygons and simply draw a single polygon encompassing them all. The file size didn't drop as significantly, but the detail didn't drop at all. Below is the comparison of the two polygon reduction techniques:

Skipped Node Polygon Reduction Edge following Polygon Reduction
2 nodes/polygon
At this stage the two outputs are identical. And xaml files sizes are identical at about 90KB.
4 nodes/polygon
You can see a little detail reduction in the skipped node version. But file size reductions are drastic. 31KB for the skipped version, 40KB for edge-following.
8 nodes/polygon
Now, the level of detail reduction in the skipped version is becoming noticable. Since this is a vector format it lends itself to panning and zooming, but at this point the loss of detail would become annoying when zoomed. However, file size reductions continue to out pace the edge following with 14KB and 27KB respectively.
16 nodes/polygon
At this stage the skipped node format is basically unusable as a representation, while the edge following still looks as crisp as the original. File size for skipped has again halved, but really is not useful. Edge following is at 21KB, clearly slowing down in file size reduction

I continued with the edge following polygon reduction technique up to 128 nodes per polygon. However by 64, the file wasn't getting any smaller anymore (the verbosity of Xaml was negligible compared to the number of polygon points. The best final file size was about 17KB, which is quite acceptable for a Silverlight application, if you ask me.

Next I need to hook this Xaml up to my InSim code and then I'll be able to render race progression. This'll have to be inside of a WPF app for now, until Silverlight's CLR gets Sockets and I can port LFSLib.NET to it. Right now, i'd have to do constant server callbacks which wouldn't scale or perform well.

Lfs State Inspector

I've been spending a lot of time, just firing up LFS, hopping through screens and catching the state events. But there's a lot of state and no good way to see what's changed (most is obvious, but some of it isn't). So i threw together a quick state inspector app that just reports the current state and uses color highlights what values have changed. In addition, the shade of the color indicates how many state changes ago it happens, as there are certain actions that cause multiple state change events to be sent and then it's easy to miss a change.

I figure, it's also a nice simple example of LFSLib.NET, so i'm releasing it both as binary and source for people to play with.

Old VS.NET 2k5 tricks

Yeah, so VS.NET 2k8 is nearly upon us, but I still manage to find tricks by accident. I guess reading the manual -- er, is there a manual? -- might have led me to this earlier, but i just came across the Ctrl-Tab menu in Visual Studio 2005.

Not only does it get you to all open files, but to any of the other panes as well. Considering that my primary reason to leave the keyboard and use the mouse is to select another file tab, this is a very welcome find.

Time Monitor example

There was a request for a Time Monitor app that would show splits and the lap time including delta's. Currently LFS, shows you your splits and laps, but only briefly and without any information about how it compares to the previous lap. But with the LFS button system, custom HUD elements can now be created relatively simply. Really, "Button" is a misnomer. It's really a label control that can be set to clickable.

I figured the time monitor would be a good example to use the RaceTracker class I wrote a couple of days ago and exercise the button system to display the data gathered by the tracker. The resulting app, is a relatively simple winforms sample (the UI exists purely for configuration) that produces LFS stats like this (click image for full screenshot):

The UI for the app itself just lets the user specify how to connect to LFS

The app is not meant for LFS servers, but as a local Aid for clients. It connects to a client instance and displays the buttons locally, according to the currently viewed player Id. I.e. it switches the hud as you tab through the players. It won't start displaying anything until it hits a first split (i.e. if you just connected and the viewed player has already past the first split, no statistics for the player will show up until the next split 1 pass.

The code is a Visual Studio Solution, created in VS 2005, although it should work fine in Visual Studio Express. It can be downloaded from here. It's written in C# and uses the LFSLib.NET library for InSim connectivity. It's not meant to be an App, and you won't get any support from me for the binary. You can run it as is, but it's meant to show how LFSLib.NET can be used for tracking and creating buttons. As such, this is example code and completely free of any license (LFSLib.NET is still governed by the GPL, though). Use it however you wish.

OutGauge Monitor Windows App example

I had a request for an example of Win Forms with OutGauge. This is a very simple project that illustrate how to quickly wire up output from OutGauge to UI. The only tricky bit for novices is the whole Invoke business. I.e. updates from outgauge come from it's listener thread. So you cannot use the event handler for outgauge to directly update your UI, or you'll get Cross-Thread exceptions. The solution is the common Invoke Required boilerplate:

private void outGaugeHandler_Updated(object sender, Gauge gauge)
{
  // this code is required for Windows Forms, since our OutGauge update
  // comes from another thread and we can only perform form updates on
  // the UI thread
  if (this.InvokeRequired)
  {
    BeginInvoke(new OutGaugeHandler.GaugeEvent(outGaugeHandler_Updated), sender, gauge);
    return;
  }

  // now we update the form with the new data

  // text boxes
  timeTextBox.Text = gauge.Time.ToString();
  carTextBox.Text = gauge.Car;

  [...]
}
The resulting App, has a single window that refreshes OutGauge updates at the interval specified in the Live For Speed cfg.txt.

The Solution for this project is for Visual Studio 2005, but should work just fine in Visual C# Express. The zip of the project can be found here

Update: LFSLib.NET 0.14b has a bug where an OutGauge ID 0 zero would cause an exception. You can avoid this by using an OutGauge ID higher than 0 or wait for 0.15b to be released. Same thing is true for OutSim.

Cross-thread data access

Continuing on my recent asynchronous UI adventures, my background object tried to access the SelectedItem of a ComboBox and I came crashing down with the dreaded Cross-Thread exception. At this point most of my code has the if(InvokeRequired) boilerplate down....

And every time i cut-and-paste that snippet and tweak if for the current method, I again wonder why the UI framework can't do some Auto-Invoking magic. But I digress.

...The scenario this time was one of data access to the plain, call BeginInvoke and return approach didn't apply. This was a scenario I hadn't yet seen. Unlike normal delegate BeginInvoke, you don't provide a callback for the EndInvoke. Control.BeginInvoke works differently, but really, it also works simpler. It's just that it's not really pointed out on MSDN how the Begin and End fit together in the scope of a Control. The other issue was that I was accessing a property, so there wasn't a simple delegate for invoking it. Instead I created a simple wrapper Accessor Method for ComboBoxen:

public delegate object GetSelectedItemDelegate(ComboBox control);

public object GetSelectedItem(ComboBox control)
{
  if (this.InvokeRequired)
  {
    IAsyncResult ar = BeginInvoke(new GetSelectedItemDelegate(GetSelectedItem), control);
    return EndInvoke(ar);
  }
  return control.SelectedItem;
}

A simple race tracking class for LFSLib.NET

Continuing in providing some usage examples for LFSLib.NET, I've created a very simple race tracking class. I figure it covers a lot of ground, since most people want to keep track of race progress, and it does show the basic use of the InSimHandler.

This class only tracks players entering and leaving and reports their split and lap times. It ignores player renames and other race information, and just spits that info out to the console. There is a static RaceTracker.Test() method that's just to be able to run the class from your Main, i.e. it's not how you'd likely use it in your actual tracking code.

using System;
using System.Collections.Generic;
using System.Text;
using FullMotion.LiveForSpeed.InSim;
using FullMotion.LiveForSpeed.InSim.EventHandlers;
using FullMotion.LiveForSpeed.InSim.Events;

namespace FullMotion.LiveForSpeed
{
  /// <summary>
  /// Simple Race Tracking example. Keeps track of player names
  /// and reports the split and lap times for each player
  /// </summary>
  public class RaceTracker
  {
    /// <summary>
    /// Just a static test call for running RaceTracker against a local LFS instance
    /// </summary>
    public static void Test()
    {
      RaceTracker tracker = new RaceTracker("127.0.0.1", 30000);
      tracker.Start();
      Console.WriteLine("Press Enter to Exit");
      Console.ReadLine();
      tracker.Stop();
    }

    InSimHandler handler;

    // state variables to make sure we don't start and stop
    // the handler multiple times
    bool started = false;
    bool running = false;

    // keep track of player names, since race tracking only gives us IDs
    Dictionary<byte, string> players = new Dictionary<byte, string>();

    /// <summary>
    /// Set up an insim handler for tracking basic race info
    /// </summary>
    /// <param name="host"></param>
    /// <param name="port"></param>
    public RaceTracker(string host, int port)
    {
      handler = new InSimHandler();
      handler.Configuration.LFSHost = host;
      handler.Configuration.LFSHostPort = port;
      handler.Configuration.UseTCP = true;
      handler.RaceTrackPlayer 
        += new RaceTrackPlayerHandler(handler_RaceTrackPlayer);
      handler.RaceTrackPlayerLeave 
        += new RaceTrackPlayerLeaveHandler(handler_RaceTrackPlayerLeave);
      handler.RaceTrackPlayerSplitTime 
        += new RaceTrackPlayerSplitTimeHandler(handler_RaceTrackPlayerSplitTime);
      handler.RaceTrackPlayerLap 
        += new RaceTrackPlayerLapHandler(handler_RaceTrackPlayerLap);
    }

    /// <summary>
    /// Connect to LFS and start tracking
    /// </summary>
    public void Start()
    {
      if (started)
      {
        throw new InvalidOperationException("RaceTracker cannot be started multiple times");
      }
      handler.Initialize();
      started = true;
      running = true;

      // make sure we get all players in the race
      handler.RequestPlayerInfo();
    }

    /// <summary>
    /// Close down the connection
    /// </summary>
    public void Stop()
    {
      if (running)
      {
        handler.Close();
        running = false;
      }
    }

    private void handler_RaceTrackPlayer(InSimHandler sender, RaceTrackPlayer e)
    {
      if (!players.ContainsKey(e.PlayerId))
      {
        players.Add(e.PlayerId, e.Playername);
        Console.WriteLine("Player joined: {0} ({1})", e.Playername, e.PlayerId);
      }
    }

    private void handler_RaceTrackPlayerLeave(InSimHandler sender, RaceTrackPlayerLeave e)
    {
      Console.WriteLine("Player left: {0} ({1})", players[e.PlayerId], e.PlayerId);
      players.Remove(e.PlayerId);
    }

    void handler_RaceTrackPlayerLap(InSimHandler sender, RaceTrackPlayerLap e)
    {
      Console.WriteLine(
        "Player '{0}': Lap {1} @ {2}:{3}.{4}",
        players[e.PlayerId],
        e.LapsDone,
        e.LapTime.Minutes,
        e.LapTime.Seconds,
        e.LapTime.Milliseconds);
    }

    void handler_RaceTrackPlayerSplitTime(InSimHandler sender, RaceTrackPlayerSplitTime e)
    {
      Console.WriteLine(
        "Player '{0}': Split {1} @ {2:00}:{3:00}.{4:000}",
        players[e.PlayerId],
        e.Split,
        e.SplitTime.Minutes,
        e.SplitTime.Seconds,
        e.SplitTime.Milliseconds);
    }
  }
}

Sample output of this running against a race of three AIs on Aston Cadet Reverse looks like this:

Press Enter to Exit
Player joined: AI 2 (6)
Player joined: AI 3 (8)
Player joined: AI 4 (10)
Player 'AI 2': Split 1 @ 00:29.870
Player 'AI 4': Split 1 @ 00:31.280
Player 'AI 3': Split 1 @ 00:31.800
Player 'AI 2': Lap 1 @ 1:5.960
Player 'AI 4': Lap 1 @ 1:9.180
Player 'AI 3': Lap 1 @ 1:10.220
Player left: AI 2 (6)
Player left: AI 3 (8)
Player 'AI 4': Split 1 @ 00:26.410
Player left: AI 4 (10)

The Player left are me manual throwing the AIs into spectate mode.

The players dictionary could easily be changed to hold a Player class instead of string as the value slot and then more data can be tracked and even a continuous log of the race results could be kept. But this should be a place to start building a race tracking application

A generic asynchronous INotifyPropertyChanged helper

The other day I was lamenting what I consider to be an omission in Data-binding's responsibilities, i.e. the lack of invocation of an INotifyPropertyChanged PropertyChanged event on the appropriate UI thread. Instead, INotifyPropertyChanged implementors are expected to be updated only on the UI thread in order to work.

I figured I should be able to throw a proxy between the actual INotifyPropertyChanged implementor and the binding, and have this proxy be instantiated with awareness of the observing form. Thus the proxy could do the invocation on the UI thread and still let me use INotifyPropertyChanged without creating a dependency on knowing that the object was being observed by a UI element. That line of thought lead to worked as a static proxy, that I had to create by hand. Once I switched to Castle's Dynamic Proxy, it didn't work anymore, the event somehow being swallowed along the way.

I also considered looking at creating my own BindingContext but that didn't bear fruit either. It was then that I realized that I didn't need to create a proxy that matched my source object, since data binding didn't care what it bound to, as long as it had the dataMember it was being told about. I started down a path of creating a wrapper class using Reflection.Emit when I further reasoned that even the dataMember that's exposed doesn't have to match the one of the data source. This opened the door to just using dynamic property invocation and a simple generic helper class emerged:

using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Windows.Forms;

namespace FullMotion.Helpers
{
  /// <summary>
  /// A helper class for creating a binding on an object that may be changed
  /// asynchronously from the bound UI thread.
  /// </summary>
  public class AsyncBindingHelper : INotifyPropertyChanged
  {
    /// <summary>
    /// Get a binding instance that can invoke a property change
    /// on the UI thread, regardless of the originating thread
    /// </summary>
    /// <param name="bindingControl">The UI control this binding is added to</param>
    /// <param name="propertyName">The property on the UI control to bind to</param>
    /// <param name="bindingSource">The source INotifyPropertyChanged to be
    /// observed for changes</param>
    /// <param name="dataMember">The property on the source to watch</param>
    /// <returns></returns>
    public static Binding GetBinding( Control bindingControl,
                                      string propertyName,
                                      INotifyPropertyChanged bindingSource,
                                      string dataMember )
    {
      AsyncBindingHelper helper 
        = new AsyncBindingHelper(bindingControl,bindingSource,dataMember);
      return new Binding(propertyName,helper,"Value");
    }

    Control bindingControl;
    INotifyPropertyChanged bindingSource;
    string dataMember;

    private AsyncBindingHelper( Control bindingControl,
                                INotifyPropertyChanged bindingSource, 
                                string dataMember )
    {
      this.bindingControl = bindingControl;
      this.bindingSource = bindingSource;
      this.dataMember = dataMember;
      bindingSource.PropertyChanged 
        += new PropertyChangedEventHandler(bindingSource_PropertyChanged);
    }

    void bindingSource_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
      if (PropertyChanged != null && e.PropertyName == dataMember)
      {
        if (bindingControl.InvokeRequired)
        {
          bindingControl.BeginInvoke(
            new PropertyChangedEventHandler(bindingSource_PropertyChanged),
            sender,
            e );
          return;
        }
        PropertyChanged(this, new PropertyChangedEventArgs("Value"));
      }
    }

    /// <summary>
    /// The current value of the data sources' datamember
    /// </summary>
    public object Value
    {
      get
      {
        return bindingSource.GetType().GetProperty(dataMember)
          .GetValue(bindingSource,null);
      }
    }
    #region INotifyPropertyChanged Members
    /// <summary>
    /// Event fired when the dataMember property on the data source is changed
    /// </summary>
    public event PropertyChangedEventHandler PropertyChanged;

    #endregion
  }
}

To use this class, simply replace this:

myLabel.DataBindings.Add("Text", myDataSource,"MyProperty");

with this:

myLabel.DataBindings.Add(
  AsyncBindingHelper.GetBinding(myLabel, "Text", myDataSource,"MyProperty") );

The one tricky thing about this is that it may cause uncollectable references. We're creating an instance of AsyncBindingHelper behind the scenes that sets up an event handler on our binding source. Which means we can't get rid of that event subscription. Theoretically, once the binding control goes out of scope, the helper should also go out of scope, relinquishing the reference it holds on the binding source.

The other thing that would be simple to do is to turn this helper into an Extension Method on INotifyPropertyChanged, once I move my code over to Orcas. That way creating an asynchronous binding on an instance of INotifyPropertyChanged would become even cleaner and straight forward.