##// END OF EJS Templates
Improved AsyncQueue...
Improved AsyncQueue Removed ImplabFx

File last commit:

r211:3eb3255d8cc5 v2
r233:d6fe09f5592c v2
Show More
StaApartment.cs
204 lines | 6.7 KiB | text/x-csharp | CSharpLexer
using Implab.Components;
using Implab.Diagnostics;
using Implab.Parallels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Implab.Fx {
public class StaApartment : RunnableComponent {
readonly Thread m_worker;
SynchronizationContext m_syncContext;
SyncContextPromise m_enterPromise;
readonly Promise m_threadStarted;
readonly Promise m_threadTerminated;
public StaApartment() : base(true) {
m_threadStarted = new Promise();
m_threadTerminated = new Promise();
m_worker = new Thread(WorkerEntry);
m_worker.SetApartmentState(ApartmentState.STA);
m_worker.IsBackground = true;
m_worker.Name = "STA managed aparment";
}
public SynchronizationContext SyncContext {
get {
if (m_syncContext == null)
throw new InvalidOperationException();
return m_syncContext;
}
}
/// <summary>
/// Returns the promise which will dispatch all handlers inside the apartment using it's <see cref="SynchronizationContext"/>
/// </summary>
/// <remarks>
/// Current implementation is optimized and will lost aync operation stack
/// </remarks>
/// <returns>The promise</returns>
public IPromise Enter() {
if (m_enterPromise == null)
throw new InvalidOperationException();
return m_enterPromise;
}
public IPromise Invoke(Action<ICancellationToken> action) {
Safe.ArgumentNotNull(action, "action");
if (m_syncContext == null)
throw new InvalidOperationException();
var p = new Promise();
var lop = TraceContext.Instance.CurrentOperation;
m_syncContext.Post(x => {
TraceContext.Instance.EnterLogicalOperation(lop, false);
try {
if (p.CancelOperationIfRequested())
return;
action(p);
p.Resolve();
} catch (Exception e) {
p.Reject(e);
} finally {
TraceContext.Instance.Leave();
}
}, null);
return p;
}
public IPromise<T> Invoke<T>(Func<ICancellationToken, T> action) {
Safe.ArgumentNotNull(action, "action");
if (m_syncContext == null)
throw new InvalidOperationException();
var p = new Promise<T>();
var lop = TraceContext.Instance.CurrentOperation;
m_syncContext.Post(x => {
TraceContext.Instance.EnterLogicalOperation(lop, false);
try {
if (p.CancelOperationIfRequested())
return;
p.Resolve(action(p));
} catch (Exception e) {
p.Reject(e);
} finally {
TraceContext.Instance.Leave();
}
}, null);
return p;
}
public IPromise Invoke(Action action) {
Safe.ArgumentNotNull(action, "action");
if (m_syncContext == null)
throw new InvalidOperationException();
var p = new Promise();
var lop = TraceContext.Instance.CurrentOperation;
m_syncContext.Post(x => {
TraceContext.Instance.EnterLogicalOperation(lop, false);
try {
if (p.CancelOperationIfRequested())
return;
action();
p.Resolve();
} catch (Exception e) {
p.Reject(e);
} finally {
TraceContext.Instance.Leave();
}
}, null);
return p;
}
public IPromise<T> Invoke<T>(Func<T> action) {
Safe.ArgumentNotNull(action, "action");
if (m_syncContext == null)
throw new InvalidOperationException();
var p = new Promise<T>();
var lop = TraceContext.Instance.CurrentOperation;
m_syncContext.Post(x => {
TraceContext.Instance.EnterLogicalOperation(lop, false);
try {
if (p.CancelOperationIfRequested())
return;
p.Resolve(action());
} catch (Exception e) {
p.Reject(e);
} finally {
TraceContext.Instance.Leave();
}
}, null);
return p;
}
/// <summary>
/// Starts the apartment thread
/// </summary>
/// <returns>Promise which will be fullfiled when the syncronization
/// context will be ready to accept tasks.</returns>
protected override IPromise OnStart() {
m_worker.Start();
return m_threadStarted;
}
/// <summary>
/// Posts quit message to the message loop of the apartment
/// </summary>
/// <returns>Promise</returns>
protected override IPromise OnStop() {
m_syncContext.Post(x => Application.ExitThread(), null);
return m_threadTerminated;
}
void WorkerEntry() {
m_syncContext = new WindowsFormsSynchronizationContext();
SynchronizationContext.SetSynchronizationContext(m_syncContext);
m_enterPromise = new SyncContextPromise(m_syncContext);
m_threadStarted.Resolve();
m_enterPromise.Resolve();
Application.OleRequired();
Application.Run();
try {
OnShutdown();
m_threadTerminated.Resolve();
} catch(Exception err) {
m_threadTerminated.Reject(err);
}
}
/// <summary>
/// Called from the STA apartment after the message loop is terminated, override this
/// method to handle apartment cleanup.
/// </summary>
protected virtual void OnShutdown() {
}
protected override void Dispose(bool disposing) {
if (disposing) {
if (!m_threadTerminated.IsResolved)
m_syncContext.Post(x => Application.ExitThread(), null);
}
base.Dispose(disposing);
}
}
}