Frage

Mit dem folgenden Code, das letzten UI-Updates in der letzten ContinueWith gemacht nie stattfinden. Ich denke, es ist wegen der Wartezeit ist () Ich am Ende haben.

Der Grund, warum ich das tue, ist, weil ohne das Warten wird das Verfahren der IDataProvider vor seinem fertigen Wesen im Hintergrund aufgebaut zurück.

Kann jemand mir helfen, bekommen dieses Recht?

Cheers,
Berryl

        private IDataProvider _buildSQLiteProvider()           
    {

        IDataProvider resultingDataProvider = null;
        ISession session = null;

        var watch = Stopwatch.StartNew();

        var uiContext = TaskScheduler.FromCurrentSynchronizationContext();

        // get the data
        var buildProvider = Task.Factory
            .StartNew(
                () =>
                    {
                        // code to build it
                    });

        // show some progress if we haven't finished
        buildProvider.ContinueWith(
            taskResult =>
            {
                // show we are making progress;
            },
            CancellationToken.None, TaskContinuationOptions.None, uiContext);

        // we have data: reflect completed status in ui 
        buildProvider.ContinueWith(
            dataProvider =>
            {
                // show we are finished;
            },
            CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiContext);

        try {
            buildProvider.Wait();
        }

        catch (AggregateException ae)
        {
            foreach (var e in ae.InnerExceptions)
                Console.WriteLine(e.Message);
        }
        Console.WriteLine("Exception handled. Let's move on.");

        CurrentSessionContext.Bind(session);

        return resultingDataProvider;
    }

====

nur klar

sein

Ich bin nicht Probleme, auf den UI-Thread zu sprechen. Die continue zuerst mit Updates der ui just fine. Das Problem ich habe, ist der Zeitpunkt der letzten Aktualisierung ui und die Rückkehr des Datenanbieters.

bemerkte ich einen Teil des Codes aus dem Geräuschpegel in tis Post zu reduzieren und auf der Aufgabe Sequenzierung zu konzentrieren.

====

ok, Arbeits Code

        private void _showSQLiteProjecPicker()           
    {

        var watch = Stopwatch.StartNew();
        var uiScheduler = TaskScheduler.FromCurrentSynchronizationContext();
        ISession session = null;

        // get the data
        var buildProvider = Task.Factory.StartNew(
                () =>
                {
                    var setProgress = Task.Factory.StartNew(
                        () =>
                        {
                            IsBusy = true;
                            Status = string.Format("Fetching data...");
                        },
                        CancellationToken.None, TaskCreationOptions.None, uiScheduler);

                    var provider = new SQLiteDataProvider();
                    session = SQLiteDataProvider.Session;
                    return provider;
                });


        buildProvider.ContinueWith(
            buildTask =>
                {
                    if(buildTask.Exception != null) {
                        Console.WriteLine(buildTask.Exception);
                    }
                    else {
                        Check.RequireNotNull(buildTask.Result);
                        Check.RequireNotNull(session);

                        _updateUiTaskIsComplete(watch);

                        CurrentSessionContext.Bind(session);
                        var provider = buildTask.Result;
                        var dao = provider.GetActivitySubjectDao();
                        var vm = new ProjectPickerViewModel(dao);
                        _showPicker(vm);
                    }
                },
            CancellationToken.None, TaskContinuationOptions.OnlyOnRanToCompletion, uiScheduler);
    }
War es hilfreich?

Lösung

aktualisieren unten
Dieser Code sieht nicht so aus, wie es TPL mir garantiert. Sieht aus wie vielleicht eine gute Verwendung für einen Background statt!

In beiden Fällen werden die Updates wahrscheinlich nicht statt, weil Sie nicht die Benutzeroberfläche von einem separaten Thread aktualisieren können - Sie brauchen, um das Update auf dem UI-Thread ausgeführt werden. Sie sollten die Dispatcher für diesen Einsatz (http://stackoverflow.com/questions/303116/system-windows-threading-dispatcher-and-winforms enthält Informationen sowohl für WPF und WinForms)
Update:

So habe ich natürlich einige der Code verpasst also hier ist eine überarbeitete Antwort. Zunächst einmal, Nicholas ist richtig - .ContinueWith gibt eine neue Aufgabe (http://msdn.microsoft.com/en-us/library/dd270696.aspx). So anstelle von

var result = Task.Factory.StartNew(...);
result.ContinueWith(...);

möchten Sie wahrscheinlich eine neue Aufgabe erstellen und dann machen alle die ContinueWith() Anrufe und assign auf die Aufgabe und dann .Start() die Aufgabe nennen. So etwas wie:

var task = new Task(...).ContinueWith(...);
task.Start();

Es gibt jedoch einen Fehler in der Konstruktion zu beginnen (wie ich es sehe)! Sie versuchen, diesen Code async zu laufen, wihch ist, warum Sie Threads und TPL verwenden. Allerdings sind rufen Sie buildProvider.Wait(); auf dem UI-Thread blockier den UI-Thread, bis diese Aufgabe abgeschlossen ist! Abgesehen von der Frage der Neulackierung der Benutzeroberfläche in den ContinueWith() während des UI-Thread blockiert ist, gibt es keinen Vorteil hier Multithreading, da Sie den UI-Thread sind blockiert (ein große no-no). Was Sie wahrscheinlich die Bind()-ing in einem ContinueWith oder etwas halten, dies zu tun mögen, dass Sie Wait() nicht anrufen und den UI-Thread blockieren.

My $ 0,02 ist, wenn Sie die Abfrage erwarten, eine lange Zeit in Anspruch zu nehmen, was Sie wirklich 2 Themen wollen (oder Aufgaben in TPL) - eine um die Abfrage durchzuführen und eine die Benutzeroberfläche in Intervallen mit Status zu aktualisieren. Wenn Sie es nicht erwarten, dass so lange dauern, ich glaube, Sie nur einen einzigen Thread wollen (Aufgabe) zur Abfrage und dann die Benutzeroberfläche aktualisiert, wenn es fertig ist. Ich würde tun dies wahrscheinlich über BackgroundWorker. TPL wurde für die Verwaltung von vielen Aufgaben gebaut und Fortsetzungen und so scheint aber übertrieben für diese Art der Sache - ich glaube, Sie könnte es tut einen Background in viel weniger Code. Aber Sie erwähnen Sie TPL verwenden, die in Ordnung ist, aber du wirst ein wenig zu überarbeiten müssen diese so, dass es tatsächlich läuft im Hintergrund!

PS - Sie wahrscheinlich die Console.WriteLine("Exception handled. Let's move on."); innerhalb des catch setzen gemeint

Andere Tipps

Ich bin ein wenig verschwommen, aber das letzte Mal habe ich die TPL Ich fand es verwirrend. ContinueWith() gibt eine neue Task Instanz. So können Sie das zweite ContinueWith() Ergebnis einer neuen Variablen zuweisen müssen, sagen var continuedTask = builderProvider.ContinueWith(...), und dann die letzte statt continuedTask.ContinueWith() zu Referenz buildProvider.ContinueWith() ändern. Dann Wait() am letzten Task.

Ich hoffe, das hilft!

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top