Великі файли Microsoft Project MPP та Primavera XER можуть займати від кількох секунд до кількох хвилин для розбору. Під час цього процесу наївний додаток виглядає замороженим: немає індикатора прогресу, немає тексту статусу, нічого, на що користувач міг би реагувати. Користувачам, які завантажують великі графіки, потрібен спосіб показати, наскільки завершене завантаження, і можливість зупинити його, якщо воно триває занадто довго.

У цьому посібнику розглядаються обидва варіанти з Aspose.Tasks for .NET. Ви створите зворотний виклик прогресу, який повідомлятиме про поточну фазу та відсоток, підключите його до процесу завантаження, забезпечите реактивність настільного інтерфейсу під час розбору у фоновому потоці та скасуєте завантаження, яке перевищує часовий бюджет.

Ключові висновки

  • IProgressNotificationCallback.Notify(ProgressNotificationArgs) — це єдиний метод, який ви реалізуєте, щоб отримувати прогрес завантаження від Aspose.Tasks for .NET.
  • ProgressNotificationArgs надає CurrentStepName, CurrentStepProgress (0–100) та EstimatedTotalProgress (0–100).
  • Прикріпіть зворотний виклик за допомогою LoadOptions.ProjectLoadingCallback; він підтримується для форматів MPP і XER.
  • Notify виконується у потоці завантаження, тому потрібно передати значення у UI‑потік перед оновленням елемента керування.
  • Скасуйте повільне завантаження, встановивши LoadOptions.CancellationToken і викликавши Cancel() у його CancellationTokenSource з іншого потоку.
  • API прогресу працює в режимі оцінки; ліцензія лише знімає обмеження розміру файлу та вихідних даних.

Вперше користуєтеся бібліотекою? Сторінка продукту Aspose.Tasks for .NET сторінка продукту та документація повністю охоплюють налаштування та ліцензування.

Як відстежувати прогрес завантаження проекту в C#?

Реалізуйте IProgressNotificationCallback, встановіть його в LoadOptions.ProjectLoadingCallback і завантажте файл через конструктор Project, який приймає LoadOptions. Мінімальний робочий код складається з трьох частин: класу зворотного виклику, екземпляра LoadOptions та виклику завантаження.

  • Input: файл MPP або XER, наприклад BigProject.mpp
  • Output: оновлення прогресу під час розбору — 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);
    }
}

Під час розбору файлу Notify виконується кілька разів, і консоль показує фазу та відсотки. Після повернення конструктора об’єкт Project повністю завантажений і готовий до використання.

Чому моніторинг прогресу завантаження важливий для великих файлів?

Він замінює незворотну паузу на видимий зворотний зв’язок, що є різницею між застосунком, який виглядає поламаним, і тим, який виглядає зайнятим. Чим більший файл, тим довше триває розбір, і тим більше «сліпе» завантаження шкодить сприйманій якості.

Конкретні використання значень прогресу:

  • Керуйте визначеним індикатором прогресу за допомогою EstimatedTotalProgress замість відображення нескінченного індикатора завантаження.
  • Реєструйте переходи CurrentStepName, щоб визначити, яка фаза домінує у часі завантаження під час профілювання повільного файлу.
  • Зберігайте реактивність інтерфейсу, завантажуючись у фоновому потоці та передаючи прогрес у UI‑потік.
  • Відображайте прогрес для кожного файлу у пакетному інструменті, який послідовно конвертує або мігрує багато проєктів.

Як встановити Aspose.Tasks та налаштувати проект?

Додайте пакет NuGet Aspose.Tasks до проєкту .NET 6 або новішого.

dotnet add package Aspose.Tasks

Або з консолі диспетчера пакетів Visual Studio:

Install-Package Aspose.Tasks

Зворотний виклик прогресу працює без ліцензії. Якщо вам потрібно завантажити файли, що перевищують обмеження розміру оцінки, або обробляти без обмежень оцінки, встановіть ліцензію один раз під час запуску:

using Aspose.Tasks;

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

Ви можете запросити безкоштовну тимчасову ліцензію на Aspose temporary license page, а також дізнатися більше про бібліотеку на Aspose.Tasks for .NET product page.

Що надає API IProgressNotificationCallback?

API — це один інтерфейс, один метод і один тип аргументу, всі в просторі імен Aspose.Tasks.

MemberTypeDescription
IProgressNotificationCallback.Notify(ProgressNotificationArgs)voidВикликається під час тривалих операцій проекту для повідомлення про прогрес.
ProgressNotificationArgs.CurrentStepNamestring (get)Назва поточної фази операції.
ProgressNotificationArgs.CurrentStepProgressint (get)Оцінений відсоток завершення поточної фази, 0–100.
ProgressNotificationArgs.EstimatedTotalProgressint (get)Оцінений відсоток завершення всієї операції, 0–100.
LoadOptions.ProjectLoadingCallbackIProgressNotificationCallback (get/set)Зворотний виклик, що викликається під час завантаження. Підтримується для MPP та XER.
LoadOptions.CancellationTokenSystem.Threading.CancellationToken (get/set)Токен, що використовується для скасування процесу завантаження.

ProgressNotificationArgs є sealed і успадковується від EventArgs. Усі три його властивості лише для читання.

Як реалізувати зворотний виклик сповіщення про прогрес?

Створіть клас, який реалізує IProgressNotificationCallback, і зробіть щось корисне з ProgressNotificationArgs всередині Notify. Залиште метод швидким, оскільки він виконується у потоці завантаження.

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

Захисник на lastTotal запобігає заповненню консолі дублюючими рядками, коли кілька викликів Notify повідомляють один і той же підсумок.

Як завантажити проєкт з відстеженням прогресу?

Встановіть ProjectLoadingCallback у об’єкті LoadOptions, а потім передайте його конструктору Project. Завантаження виконується синхронно; коли конструктор повертається, парсинг завершений.

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

Спробуєте це за власним графіком? Завантажте безкоштовну тимчасову ліцензію для запуску завантажень без обмеження оцінки розміру файлу.

Як зберегти UI реактивним під час завантаження?

Завантажуйте у фоновому потоці та передавайте значення прогресу у UI‑потік всередині зворотного виклику, оскільки Notify виконується в тому потоці, який викликав конструктор 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;
        }
    }
}

У WPF використовуйте Dispatcher.Invoke або Dispatcher.BeginInvoke замість Control.BeginInvoke.

Як скасувати довготривале завантаження?

Встановіть LoadOptions.CancellationToken у токен, отриманий з CancellationTokenSource, потім викличте Cancel() на цьому джерелі з іншого потоку. Aspose.Tasks припиняє парсинг, і конструктор Project викидає виключення, тому обгорніть його в 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);
}

Висновок

Додавання індикатора прогресу завантаження до застосунку Aspose.Tasks for .NET — це невелика зміна, яка має великий вплив на сприйману швидкість реакції. Реалізуйте IProgressNotificationCallback, призначте його для LoadOptions.ProjectLoadingCallback і читайте CurrentStepName, CurrentStepProgress та EstimatedTotalProgress у методі Notify. Додайте CancellationToken, коли завантаження може тривати досить довго, і користувач може захотіти його зупинити.

Досліджуйте документацію Aspose.Tasks for .NET та довідник API, щоб дізнатися більше, і завантажте безкоштовну тимчасову ліцензію для оцінки без обмежень.

FAQs

Чи потрібна платна ліцензія для використання API сповіщення про прогрес?
Ні. IProgressNotificationCallback працює в режимі оцінки. Тимчасова або платна ліцензія лише знімає обмеження оцінки щодо розміру файлу та вихідних даних; вона не розблоковує API прогресу.

Чи працює той самий зворотний виклик для файлів XER так само, як і для MPP?
Так. LoadOptions.ProjectLoadingCallback наразі підтримується для форматів MPP та XER. Така ж реалізація IProgressNotificationCallback обробляє обидва.

Чи є зворотний виклик прогресу потокобезпечним?
Notify викликається у потоці, який виконує завантаження, а не у фоновому потоці. У настільному застосунку перед взаємодією з індикатором прогресу передайте значення у UI‑потік за допомогою Control.Invoke або Dispatcher.Invoke.

Яка різниця між CurrentStepProgress та EstimatedTotalProgress? CurrentStepProgress — це відсоток завершення поточної фази завантаження, наприклад читання завдань або читання ресурсів. EstimatedTotalProgress — це оцінений відсоток завершення всієї операції. Обидва є цілими числами від 0 до 100.

Чи можу я скасувати завантаження всередині зворотного виклику? Не можна безпосередньо з Notify. Замість цього встановіть LoadOptions.CancellationToken у токен, отриманий від CancellationTokenSource, і викличте Cancel() на цьому джерелі з іншого потоку. Конструктор Project тоді зупиняється і викидає виключення, тому обгорніть його у try/catch.

Чи уповільнює додавання зворотного виклику завантаження?
Навантаження зворотного виклику незначне, оскільки Notify викликається лише в кількох контрольних точках, а не для кожного запису. Проте тримайте метод легким, оскільки будь-яка робота, яку ви виконуєте всередині нього, виконується в потоці завантаження.

Читати далі