Created
May 30, 2014 15:54
-
-
Save DamianReeves/76771a031f05a8be042d to your computer and use it in GitHub Desktop.
Dispatcher Issue
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Threading.Tasks; | |
namespace MyCompany.Windows.Reactive | |
{ | |
public interface ISplashPresenter | |
{ | |
Task ShowAsync(); | |
Task DisplayMessage(string messageFormat, params object[] args); | |
Task CloseAsync(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
namespace yCompany.Windows.Reactive | |
{ | |
public interface ISplashView | |
{ | |
event EventHandler Closed; | |
bool IsVisible { get; } | |
bool Activate(); | |
void Show(); | |
void Hide(); | |
void Close(); | |
object DataContext { get; set; } | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Diagnostics; | |
using System.Diagnostics.Contracts; | |
using System.Net.Mime; | |
using System.Reactive; | |
using System.Reactive.Concurrency; | |
using System.Reactive.Linq; | |
using System.Reactive.Threading.Tasks; | |
using System.Threading; | |
using System.Threading.Tasks; | |
using System.Windows; | |
using System.Windows.Navigation; | |
using System.Windows.Threading; | |
namespace MyCompany.Windows.Reactive | |
{ | |
public class SplashPresenter : ISplashPresenter | |
{ | |
private static int _threadCounter; | |
private Thread _splashThread; | |
private readonly IScheduler _splashScheduler; | |
private ISplashView _splashView; | |
private Window _dummyWindow; | |
public SplashPresenter() | |
{ | |
_splashScheduler = new EventLoopScheduler(CreateThread); | |
//SplashScheduler.Schedule(Run); | |
} | |
public IScheduler SplashScheduler | |
{ | |
get { return _splashScheduler; } | |
} | |
public ISplashView SplashView | |
{ | |
get { return _splashView; } | |
} | |
public Dispatcher SplashDispatcher { get; private set; } | |
public bool IsRunning { get; private set; } | |
public Task ShowAsync() | |
{ | |
//var tcs = new TaskCompletionSource<Unit>(); | |
return WithSplashViewAsync(splash => | |
{ | |
splash.Show(); | |
}); | |
//return tcs.Task; | |
} | |
public Task DisplayMessage(string messageFormat, params object[] args) | |
{ | |
throw new NotImplementedException(); | |
} | |
public Task CloseAsync() | |
{ | |
return WithSplashViewAsync(splash => splash.Close(), false); | |
} | |
private ISplashView GetOrCreateSplashView() | |
{ | |
var splash = SplashView; | |
if (splash == null) | |
{ | |
splash = CreateSplashView(); | |
} | |
return splash; | |
} | |
protected ISplashView CreateSplashView() | |
{ | |
return CreateCustomSplashView() ?? new SplashWindow(); | |
} | |
protected virtual ISplashView CreateCustomSplashView() | |
{ | |
return null; | |
} | |
protected Task WithSplashViewAsync(Action<ISplashView> action, bool ensureRunning = true) | |
{ | |
if (ensureRunning) | |
{ | |
return GetSplashViewAsync() | |
.ContinueWith(t => | |
{ | |
InvokeOnDispatcherAsync(() => action(t.Result)); | |
}, TaskContinuationOptions.OnlyOnRanToCompletion); | |
} | |
else | |
{ | |
var splash = SplashView; | |
if (splash != null) | |
{ | |
return InvokeOnDispatcherAsync(() => action(splash)); | |
} | |
} | |
return InvokeOnDispatcherAsync(() => { }); | |
} | |
private Task<ISplashView> GetSplashViewAsync() | |
{ | |
var tcs = new TaskCompletionSource<ISplashView>(); | |
if (IsRunning) | |
{ | |
tcs.SetResult(_splashView); | |
return tcs.Task; | |
} | |
SplashScheduler.Schedule(()=>Run(tcs.SetResult)); | |
return tcs.Task; | |
} | |
private void StartThread() | |
{ | |
} | |
private void Run(Action<ISplashView> callback) | |
{ | |
if (callback == null) throw new ArgumentNullException("callback"); | |
Contract.EndContractBlock(); | |
SplashDispatcher = Dispatcher.CurrentDispatcher; | |
SplashDispatcher.BeginInvoke((Action) (() => | |
{ | |
Dispatcher.CurrentDispatcher.ShutdownFinished += OnSplashDispatcherShutdownFinished; | |
Debug.Print("[Before] Setting IsRunning = true on Thread[{0}:{1}]", Thread.CurrentThread.Name, | |
Thread.CurrentThread.ManagedThreadId); | |
_splashView = GetOrCreateSplashView(); | |
_dummyWindow = _dummyWindow ?? CreateDummyWindow(); | |
callback(_splashView); | |
IsRunning = true; | |
Debug.Print("[After] Setting IsRunning = true on Thread[{0}:{1}]", Thread.CurrentThread.Name, | |
Thread.CurrentThread.ManagedThreadId); | |
})); | |
Debug.Print("[Before] Dispatcher.Run on Thread[{0}:{1}]", Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId); | |
Dispatcher.Run(); | |
Debug.Print("[After] Dispatcher.Run on Thread[{0}:{1}]", Thread.CurrentThread.Name, Thread.CurrentThread.ManagedThreadId); | |
IsRunning = false; | |
} | |
private void OnSplashDispatcherShutdownFinished(object sender, EventArgs e) | |
{ | |
var dispatcher = Dispatcher.FromThread(Thread.CurrentThread); | |
if (dispatcher != null) | |
{ | |
dispatcher.Invoke(() => { }); | |
} | |
SplashDispatcher = null; | |
IsRunning = false; | |
} | |
private Task InvokeOnDispatcherAsync(Action action) | |
{ | |
return SplashDispatcher.BeginInvoke(action).Task; | |
} | |
private Thread CreateThread(ThreadStart threadStart) | |
{ | |
var thread = new Thread(InterceptThreadStart(threadStart)) | |
{ | |
Name = "Splash Event Loop " + Interlocked.Increment(ref _threadCounter), | |
IsBackground = true | |
}; | |
thread.SetApartmentState(ApartmentState.STA); | |
return thread; | |
} | |
private ThreadStart InterceptThreadStart(ThreadStart threadStart) | |
{ | |
ThreadStart newThreadStart = () => | |
{ | |
Debug.WriteLine("[Begin]ThreadStart"); | |
threadStart(); | |
Debug.WriteLine("[End]Stopping thread"); | |
}; | |
return newThreadStart; | |
} | |
private Window CreateDummyWindow() | |
{ | |
var window = new Window(); | |
window.WindowState = WindowState.Minimized; | |
window.Show(); | |
window.Hide(); | |
return window; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment