// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. #if !WINDOWS using System.Reactive.Disposables; using System.Threading; namespace System.Reactive.Concurrency { /// /// Represents an object that schedules units of work on a . /// /// /// This scheduler type is typically used indirectly through the and methods that use the Dispatcher on the calling thread. /// public class DispatcherScheduler : LocalScheduler, ISchedulerPeriodic { /// /// Gets the scheduler that schedules work on the current . /// [Obsolete(Constants_WindowsThreading.OBSOLETE_INSTANCE_PROPERTY)] public static DispatcherScheduler Instance { get { return new DispatcherScheduler( #if USE_SL_DISPATCHER System.Windows.Deployment.Current.Dispatcher #else System.Windows.Threading.Dispatcher.CurrentDispatcher #endif ); } } /// /// Gets the scheduler that schedules work on the for the current thread. /// public static DispatcherScheduler Current { get { #if USE_SL_DISPATCHER return new DispatcherScheduler(System.Windows.Deployment.Current.Dispatcher); #else var dispatcher = System.Windows.Threading.Dispatcher.FromThread(Thread.CurrentThread); if (dispatcher == null) throw new InvalidOperationException(Strings_WindowsThreading.NO_DISPATCHER_CURRENT_THREAD); return new DispatcherScheduler(dispatcher); #endif } } System.Windows.Threading.Dispatcher _dispatcher; #if HAS_DISPATCHER_PRIORITY System.Windows.Threading.DispatcherPriority _priority; #endif /// /// Constructs a DispatcherScheduler that schedules units of work on the given . /// /// Dispatcher to schedule work on. /// is null. public DispatcherScheduler(System.Windows.Threading.Dispatcher dispatcher) { if (dispatcher == null) throw new ArgumentNullException("dispatcher"); _dispatcher = dispatcher; #if HAS_DISPATCHER_PRIORITY _priority = Windows.Threading.DispatcherPriority.Normal; #endif } #if HAS_DISPATCHER_PRIORITY /// /// Constructs a DispatcherScheduler that schedules units of work on the given at the given priority. /// /// Dispatcher to schedule work on. /// Priority at which units of work are scheduled. /// is null. public DispatcherScheduler(System.Windows.Threading.Dispatcher dispatcher, System.Windows.Threading.DispatcherPriority priority) { if (dispatcher == null) throw new ArgumentNullException("dispatcher"); _dispatcher = dispatcher; _priority = priority; } #endif /// /// Gets the associated with the DispatcherScheduler. /// public System.Windows.Threading.Dispatcher Dispatcher { get { return _dispatcher; } } #if HAS_DISPATCHER_PRIORITY /// /// Gets the priority at which work items will be dispatched. /// public System.Windows.Threading.DispatcherPriority Priority { get { return _priority; } } #endif /// /// Schedules an action to be executed on the dispatcher. /// /// The type of the state passed to the scheduled action. /// State passed to the action to be executed. /// Action to be executed. /// The disposable object used to cancel the scheduled action (best effort). /// is null. public override IDisposable Schedule(TState state, Func action) { if (action == null) throw new ArgumentNullException("action"); var d = new SingleAssignmentDisposable(); _dispatcher.BeginInvoke( new Action(() => { if (!d.IsDisposed) d.Disposable = action(this, state); }) #if HAS_DISPATCHER_PRIORITY , _priority #endif ); return d; } /// /// Schedules an action to be executed after dueTime on the dispatcher, using a object. /// /// The type of the state passed to the scheduled action. /// State passed to the action to be executed. /// Action to be executed. /// Relative time after which to execute the action. /// The disposable object used to cancel the scheduled action (best effort). /// is null. public override IDisposable Schedule(TState state, TimeSpan dueTime, Func action) { if (action == null) throw new ArgumentNullException("action"); var dt = Scheduler.Normalize(dueTime); if (dt.Ticks == 0) return Schedule(state, action); var d = new MultipleAssignmentDisposable(); var timer = new System.Windows.Threading.DispatcherTimer( #if HAS_DISPATCHER_PRIORITY _priority, _dispatcher #elif DESKTOPCLR40 // BACKWARDS COMPATIBILITY with v1.x System.Windows.Threading.DispatcherPriority.Background, _dispatcher #endif ); timer.Tick += (s, e) => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { try { d.Disposable = action(this, state); } finally { t.Stop(); action = null; } } }; timer.Interval = dt; timer.Start(); d.Disposable = Disposable.Create(() => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { t.Stop(); action = (_, __) => Disposable.Empty; } }); return d; } /// /// Schedules a periodic piece of work on the dispatcher, using a object. /// /// The type of the state passed to the scheduled action. /// Initial state passed to the action upon the first iteration. /// Period for running the work periodically. /// Action to be executed, potentially updating the state. /// The disposable object used to cancel the scheduled recurring action (best effort). /// is null. /// is less than TimeSpan.Zero. public IDisposable SchedulePeriodic(TState state, TimeSpan period, Func action) { if (period < TimeSpan.Zero) throw new ArgumentOutOfRangeException("period"); if (action == null) throw new ArgumentNullException("action"); var timer = new System.Windows.Threading.DispatcherTimer( #if HAS_DISPATCHER_PRIORITY _priority, _dispatcher #elif DESKTOPCLR40 // BACKWARDS COMPATIBILITY with v1.x System.Windows.Threading.DispatcherPriority.Background, _dispatcher #endif ); var state1 = state; timer.Tick += (s, e) => { state1 = action(state1); }; timer.Interval = period; timer.Start(); return Disposable.Create(() => { var t = Interlocked.Exchange(ref timer, null); if (t != null) { t.Stop(); action = _ => _; } }); } } } #endif