简体   繁体   中英

Is it OK to pass CoreDispatcher to a Singleton to auto-raise events on UI thread?

I have a Singleton class, LocationManager that handles all the Geo-Location in my Windows Metro app.

Because .PositionChanged events from the Geolocator object are often raised on a background thread, I thought of passing my class a reference to a CoreDispatcher so that it can automatically raise its own events on the UI Thread. eg:

public class LocationManager
{
    // Events
    public event EventHandler<LocationUpdatedEventArgs> LocationUpdated = delegate { };

    // Private members
    Geolocator gl = null;
    CoreDispatcher dispatcher = null;

    public void StartUpdating(CoreDispatcher dispatcher)
    {
        this.dispatcher = dispatcher;

        gl = new Geolocator();
        gl.PositionChanged += gl_PositionChanged;
    }

    async void gl_PositionChanged(Geolocator sender, PositionChangedEventArgs args)
    {
        // Ensure this class's event is raised on UI thread
        await dispatcher.RunAsync(CoreDispatcherPriority.Normal,  () => 
            {
                LocationUpdated(this,  new LocationUpdatedEventArgs(args.Position));
            }
        );   
    }

I wonder if I should be putting the dispatcher.RunAsync stuff in each of my listening UI objects instead (ie MainPage.xaml.cs) - but this approach seems to save duplication of code. Are there any drawbacks to this approach? For example, could the reference to the dispatcher ever become stale or invalid?

Have you considered the Observer Pattern ?

What you are describing sounds like a publisher-subsriber relationship. When the publisher has something to publish, all subsribers receive that publication. Your publisher does not have to be singleton, but it can be. Does that help?

Personally, I avoid placing Dispatcher (or similar) objects in any layer above the UI layer. SynchronizationContext is better.

In your case, I would take an approach using Dataflow (something very similar can be done using Rx ):

public class LocationManager
{
  // Events
  public event EventHandler<LocationUpdatedEventArgs> LocationUpdated = delegate { };

  // Private members
  Geolocator gl = null;
  ActionBlock<PositionChangedEventArgs> block = null;

  public void StartUpdating()
  {
    // Set up the block to raise our event on the UI thread.
    block = new ActionBlock<PositionChangedEventArgs>(
        args =>
        {
          LocationUpdated(this, new LocationUpdatedEventArgs(args.Position));
        },
        new ExecutionDataflowBlockOptions
        {
          TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext(),
        });

    // Start the Geolocator, sending updates to the block.
    gl = new Geolocator();
    gl.PositionChanged += (sender, args) =>
    {
      block.Post(args);
    };
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM