/
githubmirror
/
PowerToys
Обзор
Документация
Войти
/
githubmirror
/
PowerToys
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/modules/imageresizer/ui/ViewModels/ProgressViewModel.cs
134 строки
4 KB
moooyo
Migrate ImageResizer to WinUI3 (#45288)
01 апр 2026, 11:22
Не верифицирован
01 апр 2026, 11:22
ac28b1c
Код
Авторство
О чём код?
#pragma warning disable IDE0073, SA1636 // Copyright (c) Brice Lambson // The Brice Lambson licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/ #pragma warning restore IDE0073, SA1636 using System; using System.Diagnostics; using System.Globalization; using System.Linq; using System.Text; using System.Threading; using System.Threading.Tasks; using CommunityToolkit.Mvvm.ComponentModel; using CommunityToolkit.Mvvm.Input; using ImageResizer.Helpers; using ImageResizer.Models; using ImageResizer.Views; using Microsoft.UI.Dispatching; namespace ImageResizer.ViewModels { public partial class ProgressViewModel : ObservableObject, IDisposable { private readonly MainViewModel _mainViewModel; private readonly ResizeBatch _batch; private readonly IMainView _mainView; private readonly Stopwatch _stopwatch = new(); private readonly CancellationTokenSource _cancellationTokenSource = new(); private readonly DispatcherQueue _dispatcherQueue; private bool _disposedValue; [ObservableProperty] private double _progress; [ObservableProperty] [NotifyPropertyChangedFor(nameof(TimeRemainingDisplay))] private TimeSpan _timeRemaining; private static CompositeFormat _progressTimeRemainingFormat; private static CompositeFormat ProgressTimeRemainingFormat => _progressTimeRemainingFormat ??= CompositeFormat.Parse(ResourceLoaderInstance.GetString("Progress_TimeRemaining")); public string TimeRemainingDisplay { get { if (TimeRemaining == TimeSpan.MaxValue || TimeRemaining.TotalSeconds < 1) { return string.Empty; } return string.Format(CultureInfo.CurrentCulture, ProgressTimeRemainingFormat, TimeRemaining); } } public ProgressViewModel( ResizeBatch batch, MainViewModel mainViewModel, IMainView mainView) { _batch = batch; _mainViewModel = mainViewModel; _mainView = mainView; _dispatcherQueue = DispatcherQueue.GetForCurrentThread(); } [RelayCommand] public async Task StartAsync() { try { _stopwatch.Restart(); var errors = await _batch.ProcessAsync( (completed, total) => { var progress = completed / total; var timeRemaining = _stopwatch.Elapsed.Multiply((total - completed) / completed); // Progress callback runs on thread-pool threads (from Parallel.ForEachAsync), // so we must dispatch UI property updates to the UI thread. _dispatcherQueue.TryEnqueue(() => { Progress = progress; TimeRemaining = timeRemaining; }); }, _cancellationTokenSource.Token); // After await we are back on the UI thread (SynchronizationContext), // so we can update UI directly without DispatcherQueue. if (errors.Any()) { _mainViewModel.CurrentPage = new ResultsViewModel(_mainView, errors); } else { _mainView.Close(); } } catch (OperationCanceledException) { // User cancelled via Stop — window is already closing. } } [RelayCommand] public void Stop() { _cancellationTokenSource.Cancel(); _mainView.Close(); } protected virtual void Dispose(bool disposing) { if (!_disposedValue) { if (disposing) { _cancellationTokenSource.Dispose(); } _disposedValue = true; } } public void Dispose() { Dispose(disposing: true); GC.SuppressFinalize(this); } } }