繁体   English   中英

如何在非 WinForms 程序集中抽取 STA 线程?

[英]How can you pump a STA Thread in a non-WinForms assembly?

Hans 给出了这个关于抽取 STA 线程的好答案: https://stackoverflow.com/a/21684059/197229

using System;
using System.Threading;
using System.Windows.Forms;

class STAThread : IDisposable {
    public STAThread() {
        using (mre = new ManualResetEvent(false)) {
            thread = new Thread(() => {
                Application.Idle += Initialize;
                Application.Run();
            });
            thread.IsBackground = true;
            thread.SetApartmentState(ApartmentState.STA);
            thread.Start();
            mre.WaitOne();
        }
    }
    public void BeginInvoke(Delegate dlg, params Object[] args) {
        if (ctx == null) throw new ObjectDisposedException("STAThread");
        ctx.Post((_) => dlg.DynamicInvoke(args), null);
    }
    public object Invoke(Delegate dlg, params Object[] args) {
        if (ctx == null) throw new ObjectDisposedException("STAThread");
        object result = null;
        ctx.Send((_) => result = dlg.DynamicInvoke(args), null);
        return result;
    }
    protected virtual void Initialize(object sender, EventArgs e) {
        ctx = SynchronizationContext.Current;
        mre.Set();
        Application.Idle -= Initialize;
    }
    public void Dispose() {
        if (ctx != null) {
            ctx.Send((_) => Application.ExitThread(), null);
            ctx = null;
        }
    }
    private Thread thread;
    private SynchronizationContext ctx;
    private ManualResetEvent mre;
}

But it relies on calls like Application.Run which is a Windows Forms class, I don't think I want in a non-UI static library.

那么有没有办法调整它,或者它甚至可以按原样使用?

您可以使用 Stephen Cleary 的Nito.AsyncEx.Context nuget 中的AsyncContextThread 来自其github 描述

AsyncContextThread 提供可用于在该线程上安排任务的属性。

nuget 包含SynchronizationContext的自定义实现,因此代码可以很容易地重写,例如:

using System;
using System.Threading;
using Nito.AsyncEx;

class STAThread : IDisposable
{
    public STAThread()
    {
        ctx = new AsyncContextThread();
    }

    public void BeginInvoke(Delegate dlg, params Object[] args)
    {
        ctx.Context.SynchronizationContext
            .Post((_) => dlg.DynamicInvoke(args), null);
    }

    public object Invoke(Delegate dlg, params Object[] args)
    {
        object result = null;
        ctx.Context.SynchronizationContext
            .Send((_) => result = dlg.DynamicInvoke(args), null);
        return result;
    }
    
    public void Dispose()
    {
        ctx.JoinAsync().GetAwaiter().GetResult();
        ctx.Dispose();
    }

    private readonly AsyncContextThread ctx;
}

顺便说一句,从这篇 MSDN 文章中,并非SynchronizationContext的所有实现都保证委托将在特定线程上执行,而 WinForms 和 WPF SynchronizationContext保证默认和 ASP.NET 不保证。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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