web-dev-qa-db-fra.com

Définir ApartmentState sur une tâche

J'essaie de définir l'état de l'appartement sur une tâche, mais je ne vois aucune option pour ce faire. Existe-t-il un moyen de le faire en utilisant une tâche?

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

Lorsque StartNew échoue, faites-le vous-même:

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

(Vous pouvez en créer un pour Task qui sera presque identique, ou ajouter des surcharges pour certaines des différentes options de StartNew.)

85
Servy

Une surcharge de la réponse de Servy pour démarrer une tâche nulle

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

Vous pouvez par exemple créer une nouvelle tâche comme suit:

       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;
            }
        }
13
BEN'S

C'est ce que j'utilise avec Action car je n'ai rien à retourner:

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

Où je l'appelle comme ça:

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

Pour plus de détails, veuillez consulter https://github.com/xunit/xunit/issues/1 et Func vs Action vs Predicate

Pour info, c'est l'exception que j'obtenais là où j'avais besoin de définir l'état de l'appartement:

System.InvalidOperationException s'est produite HResult = -2146233079
Message = Le thread appelant doit être STA, car de nombreux composants d'interface utilisateur l'exigent. Source = PresentationCore StackTrace: à System.Windows.Input.InputManager..ctor () à System.Windows.Input.InputManager.GetCurrentInputManagerImpl () à System.Windows.Input.Keyboard.ClearFocus ()

1
user8128167