在任务上设置ApartmentState

时间:2013-05-23 17:42:02

标签: c# task

我正在尝试在任务上设置公寓状态,但在执行此操作时看不到任何选项。有没有办法使用任务执行此操作?

for (int i = 0; i < zom.Count; i++)
{
     Task t = Task.Factory.StartNew(zom[i].Process);
     t.Wait();
}

6 个答案:

答案 0 :(得分:83)

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的各种选项添加重载。)

答案 1 :(得分:14)

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;
}

答案 2 :(得分:12)

您可以按照以下方式创建新任务:

       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;
            }
        }

答案 3 :(得分:1)

这是Task构造函数和RunSynchronously方法的好用例。

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

TaskCreationOptions.DenyChildAttach的目的是使所得任务的行为与Servy的solution相同(不可能将子任务附加到父TaskCompletionSource.Task)。 Task.Run方法的行为也是拒绝孩子的依恋。

答案 4 :(得分:0)

如果需要为Task提供一个CancellationToken,则可以在任务操作中启动STA线程并按如下所示加入STA线程:

var task = Task.Factory.StartNew(() =>
{
    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();
    thread.Join();
}, cancellationToken);

答案 5 :(得分:-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()

相关问题