##// END OF EJS Templates
Code review for RunnableComponent...
Code review for RunnableComponent Added StaApartment class based on System.Windows.Forms.Application message loop

File last commit:

r210:5dc21f6a3222 v2
r210:5dc21f6a3222 v2
Show More
StaApartment.cs
188 lines | 6.0 KiB | text/x-csharp | CSharpLexer
cin
Code review for RunnableComponent...
r210 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;
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;
}
}
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_threadStarted.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);
}
}
}