Jelajahi Sumber

ProgressObserver

龙腾猫跃 4 bulan lalu
induk
melakukan
2d811e8f58
2 mengubah file dengan 50 tambahan dan 1 penghapusan
  1. 28 1
      Shared/General/Progress.cs
  2. 22 0
      Tests/General/ProgressTest.cs

+ 28 - 1
Shared/General/Progress.cs

@@ -54,7 +54,7 @@ public class ProgressProvider {
     private readonly List<(double percentage, ProgressProvider sub)> childrens = [];
 
     /// <summary>
-    /// 拆分一个子项:当该子项完成时,当前进度将增至 <paramref name="value"/>。
+    /// 拆分一个子项:当该子项完成时,进度将从当前值增加至 <paramref name="value"/>。
     /// </summary>
     public ProgressProvider SplitTo(double value) {
         lock (this) return SplitBy(value - progressSum).First();
@@ -117,3 +117,30 @@ public class ProgressProvider {
     }
 
 }
+
+/// <summary>
+/// 监听进度变化,并将观测到的进度节流后传给更新方法。
+/// </summary>
+public class ProgressObserver : IDisposable {
+    private readonly ProgressProvider provider;
+    private readonly RateLimitedAction updateAction;
+
+    public ProgressObserver(ProgressProvider provider, Action<double> updateAction, double minimalIntervalMs = 70) {
+        this.provider = provider;
+        this.updateAction = Throttler.Throttle(() => updateAction(provider.Observe()), 
+            TimeSpan.FromMilliseconds(minimalIntervalMs), leading: true, trailing: true);
+        provider.ProgressChanged += OnProgressChanged;
+    }
+
+    private void OnProgressChanged() {
+        if (!disposed) updateAction.Invoke();
+    }
+
+    private bool disposed = false;
+    public void Dispose() {
+        if (disposed) return;
+        disposed = true;
+        provider.ProgressChanged -= OnProgressChanged;
+        updateAction.Dispose();
+    }
+}

+ 22 - 0
Tests/General/ProgressTest.cs

@@ -43,4 +43,26 @@ public class ProgressTest : TestBase {
         await Assert.That(Math.Abs(progress.Observe() - 2.0 / 3) < 0.000001).IsTrue();
     }
 
+    [Test]
+    public async Task ProgressObserver_监听进度变化并更新UI() {
+        var progress = new ProgressProvider();
+        int updateCount = 0;
+        double updatedProgress = 0;
+
+        using (var observer = new ProgressObserver(progress, value => {
+            updateCount++;
+            updatedProgress = value;
+        }, TimeSpan.FromHours(1))) {
+            progress.Set(0.25);
+
+            await Assert.That(updateCount).IsEqualTo(1);
+            await Assert.That(updatedProgress).IsEqualTo(0.25);
+        }
+
+        progress.Set(0.5);
+        await Task.Delay(50);
+
+        await Assert.That(updateCount).IsEqualTo(1);
+    }
+
 }