Duże pliki Microsoft Project MPP i Primavera XER mogą wymagać od kilku sekund do kilku minut na przetworzenie. Podczas tego działania prosta aplikacja wydaje się zawieszona: brak paska postępu, brak tekstu statusu, nic, na co użytkownik mógłby zareagować. Każdy, kto ładuje duże harmonogramy, potrzebuje sposobu na pokazanie, jak daleko postępuje ładowanie, oraz sposobu na zatrzymanie go, jeśli trwa zbyt długo.

Ten przewodnik obejmuje oba przypadki z Aspose.Tasks for .NET. Zbudujesz wywołanie zwrotne postępu, które raportuje bieżącą fazę i procent, podłączysz je do ładowania, utrzymasz responsywny interfejs użytkownika na pulpicie, podczas gdy parsowanie działa w tle, oraz anulujesz ładowanie, które przekracza przydzielony limit czasu.

Najważniejsze wnioski

  • IProgressNotificationCallback.Notify(ProgressNotificationArgs) jest jedyną metodą, którą implementujesz, aby otrzymywać postęp ładowania z Aspose.Tasks for .NET.
  • ProgressNotificationArgs udostępnia CurrentStepName, CurrentStepProgress (0–100) oraz EstimatedTotalProgress (0–100).
  • Dołącz wywołanie zwrotne za pomocą LoadOptions.ProjectLoadingCallback; jest ono obsługiwane dla formatów MPP i XER.
  • Notify działa w wątku ładowania, więc przekaż wartości do wątku UI przed aktualizacją kontrolki.
  • Anuluj wolne ładowanie, ustawiając LoadOptions.CancellationToken i wywołując Cancel() na jego CancellationTokenSource z innego wątku.
  • API postępu działa w trybie ewaluacyjnym; licencja usuwa jedynie ograniczenia rozmiaru pliku i limitów wyjścia.

Nowy w bibliotece? Strona produktu Aspose.Tasks for .NET oraz dokumentacja zawierają pełne informacje o konfiguracji i licencjonowaniu.

Jak monitorować postęp ładowania projektu w C#?

Zaimplementuj IProgressNotificationCallback, ustaw go w LoadOptions.ProjectLoadingCallback i wczytaj plik przy użyciu konstruktora Project, który przyjmuje LoadOptions. Minimalny działający kod składa się z trzech części: klasy callback, instancji LoadOptions oraz wywołania ładowania.

  • Input: plik MPP lub XER, na przykład BigProject.mpp
  • Output: aktualizacje postępu podczas parsowania — CurrentStepName, CurrentStepProgress, EstimatedTotalProgress
  • Library: Aspose.Tasks for .NET
  • Language: C#
using System;
using Aspose.Tasks;

internal sealed class ConsoleProgressCallback : IProgressNotificationCallback
{
    public void Notify(ProgressNotificationArgs args)
    {
        Console.WriteLine(
            "{0}: step {1}% / total {2}%",
            args.CurrentStepName,
            args.CurrentStepProgress,
            args.EstimatedTotalProgress);
    }
}

internal static class Program
{
    private static void Main()
    {
        // A license is optional here. Uncomment to remove evaluation limits.
        // new License().SetLicense("Aspose.Tasks.lic");

var loadOptions = new LoadOptions
        {
            ProjectLoadingCallback = new ConsoleProgressCallback()
        };

var project = new Project("BigProject.mpp", loadOptions);

Console.WriteLine("Loaded {0} top-level tasks.", project.RootTask.Children.Count);
    }
}

Podczas parsowania pliku, Notify uruchamia się wielokrotnie, a konsola wyświetla fazę i procenty. Po powrocie z konstruktora obiekt Project jest w pełni załadowany i gotowy do użycia.

Dlaczego monitorowanie postępu ładowania ma znaczenie przy dużych plikach?

Zastępuje nieodpowiadającą przerwę widoczną informacją zwrotną, co stanowi różnicę między aplikacją wyglądającą na zepsutą a taką, która wygląda na zajętą. Im większy plik, tym dłuższe parsowanie, a tym samym „ślepe” ładowanie kosztuje Cię więcej w postrzeganej jakości.

Konkretne zastosowania wartości postępu:

  • Steruj określonym paskiem postępu przy użyciu EstimatedTotalProgress zamiast wyświetlania nieokreślonego wskaźnika.
  • Rejestruj przejścia CurrentStepName, aby ustalić, która faza dominuje czas ładowania podczas profilowania wolnego pliku.
  • Utrzymuj responsywność interfejsu, ładując w tle i publikując postęp na wątek UI.
  • Wyświetlaj postęp dla każdego pliku w narzędziu wsadowym, które konwertuje lub migruje wiele projektów kolejno.

Jak zainstalować Aspose.Tasks i skonfigurować projekt?

Dodaj pakiet NuGet Aspose.Tasks do projektu .NET 6 lub nowszego.

dotnet add package Aspose.Tasks

Lub, z konsoli Menedżera pakietów Visual Studio:

Install-Package Aspose.Tasks

Wywołanie zwrotne postępu działa bez licencji. Jeśli potrzebujesz wczytywać pliki powyżej limitu rozmiaru w wersji ewaluacyjnej lub przetwarzać je bez ograniczeń ewaluacji, ustaw licencję raz przy uruchamianiu:

using Aspose.Tasks;

var license = new License();
license.SetLicense("Aspose.Tasks.lic");

Możesz poprosić o darmową tymczasową licencję na stronie tymczasowej licencji Aspose, a także przeczytać więcej o bibliotece na stronie produktu Aspose.Tasks for .NET.

Co zapewnia interfejs API IProgressNotificationCallback?

API składa się z jednego interfejsu, jednej metody i jednego typu argumentu, wszystkie w przestrzeni nazw Aspose.Tasks.

CzłonekTypOpis
IProgressNotificationCallback.Notify(ProgressNotificationArgs)voidWywoływane podczas długotrwałych operacji projektu w celu raportowania postępu.
ProgressNotificationArgs.CurrentStepNamestring (get)Nazwa bieżącej fazy operacji.
ProgressNotificationArgs.CurrentStepProgressint (get)Szacowany procent ukończenia bieżącej fazy, 0–100.
ProgressNotificationArgs.EstimatedTotalProgressint (get)Szacowany procent ukończenia całej operacji, 0–100.
LoadOptions.ProjectLoadingCallbackIProgressNotificationCallback (get/set)Wywoływane wywołanie zwrotne podczas ładowania. Obsługiwane dla MPP i XER.
LoadOptions.CancellationTokenSystem.Threading.CancellationToken (get/set)Token używany do anulowania trwającego ładowania.

ProgressNotificationArgs jest sealed i dziedziczy po EventArgs. Wszystkie trzy jej właściwości są tylko do odczytu.

Jak zaimplementować wywołanie zwrotne powiadomienia o postępie?

Utwórz klasę, która implementuje IProgressNotificationCallback i zrób coś przydatnego z ProgressNotificationArgs wewnątrz Notify. Zachowaj metodę szybką, ponieważ jest uruchamiana w wątku ładowania.

using System;
using Aspose.Tasks;

internal sealed class ConsoleProgressCallback : IProgressNotificationCallback
{
    private int lastTotal = -1;

public void Notify(ProgressNotificationArgs args)
    {
        // Only redraw when the total percentage actually changes.
        if (args.EstimatedTotalProgress == lastTotal)
        {
            return;
        }

lastTotal = args.EstimatedTotalProgress;
        Console.WriteLine("[{0,3}%] {1}", args.EstimatedTotalProgress, args.CurrentStepName);
    }
}

Zabezpieczenie na lastTotal zapobiega zalewaniu konsoli duplikatowymi wierszami, gdy kilka wywołań Notify zgłasza tę samą sumę.

Jak załadować projekt z śledzeniem postępu?

Ustaw ProjectLoadingCallback na obiekcie LoadOptions, a następnie przekaż go do konstruktora Project. Ładowanie odbywa się synchronicznie; gdy konstruktor zwróci, parsowanie jest zakończone.

using System;
using Aspose.Tasks;

internal static class Loader
{
    public static Project Load(string path)
    {
        var loadOptions = new LoadOptions
        {
            ProjectLoadingCallback = new ConsoleProgressCallback()
        };

// Same call for MPP and XER; only the file path changes.
        var project = new Project(path, loadOptions);

Console.WriteLine("Done. Root task children: {0}", project.RootTask.Children.Count);
        return project;
    }
}

Czy próbujesz tego w własnych harmonogramach? Pobierz darmową tymczasową licencję aby uruchamiać obciążenia bez limitu oceny rozmiaru pliku.

Jak utrzymać responsywny interfejs użytkownika podczas ładowania?

Załaduj w wątku w tle i przekaż wartości postępu do wątku interfejsu użytkownika w obrębie wywołania zwrotnego, ponieważ Notify działa w wątku, który wywołał konstruktor Project.

using System.Windows.Forms;
using Aspose.Tasks;

internal sealed class ProgressBarCallback : IProgressNotificationCallback
{
    private readonly ProgressBar bar;

public ProgressBarCallback(ProgressBar bar) => this.bar = bar;

public void Notify(ProgressNotificationArgs args)
    {
        if (bar.InvokeRequired)
        {
            bar.BeginInvoke(() => bar.Value = args.EstimatedTotalProgress);
        }
        else
        {
            bar.Value = args.EstimatedTotalProgress;
        }
    }
}

W WPF użyj Dispatcher.Invoke lub Dispatcher.BeginInvoke zamiast Control.BeginInvoke.

Jak anulować długotrwałe ładowanie?

Ustaw LoadOptions.CancellationToken na token pochodzący z CancellationTokenSource, a następnie wywołaj Cancel() na tym źródle z innego wątku. Aspose.Tasks przestaje parsować i konstruktor Project zgłasza wyjątek, więc otocz go blokiem try/catch.

using System;
using System.Threading;
using Aspose.Tasks;

var cts = new CancellationTokenSource();

var loadOptions = new LoadOptions
{
    ProjectLoadingCallback = new ConsoleProgressCallback(),
    CancellationToken = cts.Token
};

// Wire a Cancel button or a timeout to this:
// cts.CancelAfter(TimeSpan.FromSeconds(30));

try
{
    var project = new Project("BigProject.xer", loadOptions);
    Console.WriteLine("Loaded {0} tasks.", project.RootTask.Children.Count);
}
catch (Exception ex)
{
    Console.WriteLine("Load stopped: {0}", ex.Message);
}

Wnioski

Dodanie informacji o postępie ładowania do aplikacji Aspose.Tasks for .NET to niewielka zmiana, która ma duży wpływ na postrzeganą responsywność. Zaimplementuj IProgressNotificationCallback, przypisz go do LoadOptions.ProjectLoadingCallback i odczytuj CurrentStepName, CurrentStepProgress oraz EstimatedTotalProgress wewnątrz Notify. Dodaj CancellationToken, gdy ładowania mogą trwać wystarczająco długo, aby użytkownik chciał je zatrzymać.

Przeglądaj Aspose.Tasks for .NET dokumentacja i referencję API, aby iść dalej, oraz pobierz darmową tymczasową licencję, aby ocenić bez ograniczeń.

Najczęściej zadawane pytania

Czy potrzebuję płatnej licencji, aby używać API powiadomień o postępie? Nie. IProgressNotificationCallback działa w trybie ewaluacyjnym. Tymczasowa lub płatna licencja usuwa jedynie ograniczenia ewaluacyjne dotyczące rozmiaru pliku i wyjścia; nie odblokowuje ona API postępu.

Czy ten sam callback działa dla plików XER, tak samo jak dla MPP? Tak. LoadOptions.ProjectLoadingCallback jest obecnie obsługiwany dla formatów MPP i XER. Ta sama implementacja IProgressNotificationCallback obsługuje oba.

Czy wywołanie zwrotne postępu jest wątkowo‑bezpieczne?
Notify jest wywoływane w wątku, który wykonuje ładowanie, a nie w wątku tła. W aplikacji desktopowej należy przekazać wartości do wątku interfejsu użytkownika przy użyciu Control.Invoke lub Dispatcher.Invoke przed manipulacją paskiem postępu.

Jaka jest różnica między CurrentStepProgress a EstimatedTotalProgress?
CurrentStepProgress to procent ukończenia bieżącej fazy ładowania, takiej jak odczytywanie zadań lub odczytywanie zasobów. EstimatedTotalProgress to szacowany procent ukończenia całej operacji. Oba są liczbami całkowitymi od 0 do 100.

Czy mogę anulować ładowanie z wnętrza wywołania zwrotnego?
Nie bezpośrednio z wnętrza Notify. Zamiast tego ustaw LoadOptions.CancellationToken na token pochodzący z CancellationTokenSource i wywołaj Cancel() na tym źródle z innego wątku. Konstruktor Project wtedy zatrzyma się i zgłosi wyjątek, więc otocz go blokiem try/catch.

Czy dodanie callbacka spowalnia ładowanie?
Obciążenie wywołania zwrotnego jest pomijalne, ponieważ Notify jest wywoływany w niewielkiej liczbie punktów kontrolnych, a nie dla każdego rekordu. Należy jednak utrzymać metodę lekką, ponieważ wszelka praca wykonywana w jej wnętrzu odbywa się na wątku ładowania.

Czytaj więcej