Большие файлы 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 и вызова загрузки.
- Ввод: файл MPP или XER, например
BigProject.mpp - Вывод: обновления прогресса во время разбора —
CurrentStepName,CurrentStepProgress,EstimatedTotalProgress - Библиотека: Aspose.Tasks for .NET
- Язык: 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, загружая данные в фоновом потоке и передавая прогресс в UI‑поток.
- Показывайте прогресс для каждого файла в пакетном инструменте, который последовательно конвертирует или мигрирует множество проектов.
Как установить Aspose.Tasks и настроить проект?
Добавьте пакет NuGet Aspose.Tasks в проект .NET 6 или более поздней версии.
dotnet add package Aspense.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.
| Член | Тип | Описание |
|---|---|---|
IProgressNotificationCallback.Notify(ProgressNotificationArgs) | void | Вызывается во время длительных операций проекта для сообщения о прогрессе. |
ProgressNotificationArgs.CurrentStepName | string (get) | Имя текущей фазы операции. |
ProgressNotificationArgs.CurrentStepProgress | int (get) | Оценочный процент завершения текущей фазы, 0–100. |
ProgressNotificationArgs.EstimatedTotalProgress | int (get) | Оценочный процент завершения всей операции, 0–100. |
LoadOptions.ProjectLoadingCallback | IProgressNotificationCallback (get/set) | Обратный вызов, вызываемый во время загрузки. Поддерживается для MPP и XER. |
LoadOptions.CancellationToken | System.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‑поток внутри обратного вызова, потому что 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, чтобы узнать больше, а также скачайте бесплатную временную лицензию для неограниченной оценки.
Часто задаваемые вопросы
Нужна ли платная лицензия для использования 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 вызывается лишь в небольшом числе контрольных точек, а не для каждой записи. Тем не менее, держите метод легковесным, поскольку любая работа, выполненная внутри него, выполняется в потоке загрузки.
