在任务上设置 ApartmentState

问题描述 投票:0回答:5

我正在尝试设置任务的公寓状态,但没有看到执行此操作的选项。有没有办法使用任务来做到这一点?

for (int i = 0; i < zom.Count; i++)
{
     Task t = Task.Factory.StartNew(zom[i].Process);
     t.Wait();
}
c# task task-parallel-library
5个回答
105
投票

StartNew
失败时,你就自己做:

public static Task<T> StartSTATask<T>(Func<T> func)
{
    var tcs = new TaskCompletionSource<T>();
    Thread thread = new Thread(() =>
    {
        try
        {
            tcs.SetResult(func());
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return tcs.Task;
}

(您可以为

Task
创建一个看起来几乎相同的,或者为
StartNew
具有的一些不同选项添加重载。)


23
投票

启动无效任务的 Servy 答案超载

public static Task StartSTATask(Action func)
{
    var tcs = new TaskCompletionSource<object>();
    var thread = new Thread(() =>
    {
        try
        {
            func();
            tcs.SetResult(null);
        }
        catch (Exception e)
        {
            tcs.SetException(e);
        }
    });
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return tcs.Task;
}

13
投票

例如,您可以按如下方式创建新任务:

       try
        {
            Task reportTask = Task.Factory.StartNew(
                () =>
                {
                    Report report = new Report(this._manager);
                    report.ExporterPDF();
                }
                , CancellationToken.None
                , TaskCreationOptions.None
                , TaskScheduler.FromCurrentSynchronizationContext()
                );

            reportTask.Wait();
        }
        catch (AggregateException ex)
        {
            foreach(var exception in ex.InnerExceptions)
            {
                throw ex.InnerException;
            }
        }

5
投票

这是

Task
构造函数和
RunSynchronously
方法的一个很好的用例。

public static Task<T> RunSTATask<T>(Func<T> function)
{
    Task<T> task = new(function, TaskCreationOptions.DenyChildAttach);
    Thread thread = new(() => task.RunSynchronously());
    thread.IsBackground = true;
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    return task;
}

TaskCreationOptions.DenyChildAttach
的目的是使结果任务的行为与Servy的解决方案相同(无法将子任务附加到父任务
TaskCompletionSource.Task
)。拒绝孩子依恋也是
Task.Run
方法的行为。


1
投票

这就是我在 Action 中使用的,因为我不需要返回任何内容:

public static class TaskUtil
{
    public static Task StartSTATask(Action action)
    {
        var tcs = new TaskCompletionSource<object>();
        var thread = new Thread(() =>
        {
            try
            {
                action();
                tcs.SetResult(new object());
            }
            catch (Exception e)
            {
                tcs.SetException(e);
            }
        });
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
        return tcs.Task;
    }
}

我这样称呼它:

TaskUtil.StartSTATask(async () => await RefreshRecords());

详情请参阅https://github.com/xunit/xunit/issues/103Func vs. Action vs. Predicate

仅供参考,这是我需要设置公寓状态的例外情况:

发生System.InvalidOperationException HResult=-2146233079
Message=调用线程必须是STA,因为UI组件很多 需要这个。来源=PresentationCore StackTrace: 在 System.Windows.Input.InputManager..ctor() 在 System.Windows.Input.InputManager.GetCurrentInputManagerImpl() 在 System.Windows.Input.Keyboard.ClearFocus()

© www.soinside.com 2019 - 2024. All rights reserved.