tags:

views:

40

answers:

1

Hi,

I'm trying to write an application which monitors the location of the computer using the .net 4.0 System.Device.Location namespace. However I'm finding that the GeoCoordinateWatcher.PositionChanged event is only fired when I register with the event on the class, and not when I use the interface it implements.

Here is a working version of the code:

using (GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher())
{
    geoCoordinateWatcher.PositionChanged += (sender, args) => Console.WriteLine(args.Position);
    geoCoordinateWatcher.Start();

    Thread.Sleep(2000);
}

This outputs the position object as I would expect. When I change the code to this:

using (GeoCoordinateWatcher geoCoordinateWatcher = new GeoCoordinateWatcher())
{
    IGeoPositionWatcher<GeoCoordinate> positionWatcher = geoCoordinateWatcher;
    positionWatcher.PositionChanged += (sender, args) => Console.WriteLine(args.Position);
    positionWatcher.Start();

    Thread.Sleep(2000);
}

it doesn't output anything. I want to use the interface so that it's easier to unit test the code.

What am I doing wrong? Is there something subtle I'm misunderstanding about events on generic interfaces?

Thanks

Andy

EDIT:

I think this may be a bug in Microsoft's code. I had a look at System.Device.dll in .net reflector and found that the GeoCoordinateWatcher has 2 implementations of PositionChanged event. The first a direct implementation of its own PositionChanged Event, the second is a explicit implementation of the IGeoPositionWatcher.PositionChanged event.

The second one appear not to be used anywhere else in the code.

I also managed to find a quick workaround by deriving from GeoCoordinateWatcher, and implementing the interfaces PositionChanged event myself:

public class MyGeoCoordinateWatcher : GeoCoordinateWatcher, IGeoPositionWatcher<GeoCoordinate>
{
    event EventHandler<GeoPositionChangedEventArgs<GeoCoordinate>> IGeoPositionWatcher<GeoCoordinate>.PositionChanged
    {
        add { base.PositionChanged += value; }
        remove { base.PositionChanged -= value; }
    }
}

Now if I create a MyGeoCoordinateWatcher instead both sets of the above code work.

Can anyone confirm this?

Thanks

EDIT:

Raised this on Microsoft Connect: https://connect.microsoft.com/VisualStudio/feedback/details/613235/igeopositionwatcher-geocoordinate-positionchanged-event-does-not-fire-on-geocoordinatewatcher-class

+1  A: 

I completely agree with your diagnosis, nice sleuthing. The explicit interface implementation is updating a field named m_positionChanged. The PositionChanged event is updating a delegate field named PositionChanged.

Inspiring to see the big boys fumble this. No simple workaround for this beyond hacking reflection to access the private fields directly. You can report the bug at connect.microsoft.com. Just a link to this thread should give them everything they need.

Hans Passant
I have tried the code in Unit tests, Console apps and WPF apps and the behaviour is the same in each. I've added my latest findings to the original question.
Andy Lowry
You've got it. Post updated.
Hans Passant