diff --git a/App/App.csproj b/App/App.csproj
index c514219..59376d3 100644
--- a/App/App.csproj
+++ b/App/App.csproj
@@ -16,7 +16,7 @@
10.0.22000.0
PerMonitorV2
AnyCPU;x64;ARM64;x86
- 2.1.4
+ 2.1.5
https://github.com/soleon/Percentage
https://github.com/soleon/Percentage?tab=MIT-1-ov-file
Icon.png
diff --git a/App/App.xaml.cs b/App/App.xaml.cs
index 59fb44a..f8e0d0c 100644
--- a/App/App.xaml.cs
+++ b/App/App.xaml.cs
@@ -55,11 +55,19 @@ public App()
ShutdownMode = ShutdownMode.OnExplicitShutdown;
- DispatcherUnhandledException += (_, e) => HandleException(e.Exception);
+ DispatcherUnhandledException += (_, e) =>
+ {
+ HandleException(e.Exception);
+ e.Handled = true;
+ };
AppDomain.CurrentDomain.UnhandledException += (_, e) => HandleException(e.ExceptionObject);
- TaskScheduler.UnobservedTaskException += (_, e) => HandleException(e.Exception);
+ TaskScheduler.UnobservedTaskException += (_, e) =>
+ {
+ HandleException(e.Exception);
+ e.SetObserved();
+ };
InitializeComponent();
diff --git a/App/Extensions/DelegateExtensions.cs b/App/Extensions/DelegateExtensions.cs
new file mode 100644
index 0000000..d7e4300
--- /dev/null
+++ b/App/Extensions/DelegateExtensions.cs
@@ -0,0 +1,24 @@
+using System;
+
+namespace Percentage.App.Extensions;
+
+internal static class DelegateExtensions
+{
+ private const int DefaultMaxRetryCount = 5;
+
+ internal static void RetryOnException(this Action action, Action onRetryFailed = null,
+ int maxRetryCount = DefaultMaxRetryCount) where T : Exception
+ {
+ var lastRetry = maxRetryCount - 1;
+ for (var i = 0; i < maxRetryCount; i++)
+ try
+ {
+ action();
+ return;
+ }
+ catch (T e)
+ {
+ if (i == lastRetry) onRetryFailed?.Invoke(e);
+ }
+ }
+}
\ No newline at end of file
diff --git a/App/Extensions/NotifyIconExtensions.cs b/App/Extensions/NotifyIconExtensions.cs
index 954bf6f..b804c54 100644
--- a/App/Extensions/NotifyIconExtensions.cs
+++ b/App/Extensions/NotifyIconExtensions.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
@@ -11,16 +12,27 @@ internal static class NotifyIconExtensions
{
private const double DefaultNotifyIconSize = 16;
+ internal static void SetBatteryFullIcon(this NotifyIcon notifyIcon)
+ {
+ notifyIcon.SetIcon(new TextBlock
+ {
+ Text = "\uf5fc",
+ Foreground = BrushExtensions.GetBatteryNormalBrush(),
+ FontFamily = new FontFamily("Segoe Fluent Icons"),
+ FontSize = 16
+ });
+ }
+
internal static void SetIcon(this NotifyIcon notifyIcon, FrameworkElement textBlock)
{
// Measure the size of the element first.
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
-
+
// Use the desired size to work out the appropriate margin so that the element can be centre aligned in the
// tray icon's 16-by-16 region.
textBlock.Margin = new Thickness((DefaultNotifyIconSize - textBlock.DesiredSize.Width) / 2,
(DefaultNotifyIconSize - textBlock.DesiredSize.Height) / 2, 0, 0);
-
+
// Measure again for the correct desired size with the margin.
textBlock.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
textBlock.Arrange(new Rect(textBlock.DesiredSize));
@@ -33,34 +45,15 @@ internal static void SetIcon(this NotifyIcon notifyIcon, FrameworkElement textBl
dpiScale.PixelsPerInchX,
dpiScale.PixelsPerInchY,
PixelFormats.Default);
- renderTargetBitmap.Render(textBlock);
- // There's a chance that some native exception may be thrown when setting the icon's image.
- // Catch any exception here and retry a few times then fail silently with logs.
- for (var i = 0; i < 5; i++)
- try
- {
- notifyIcon.Icon = renderTargetBitmap;
- App.SetTrayIconUpdateError(null);
- break;
- }
- catch (Exception e)
- {
- if (i == 4)
- // Retried maximum number of times.
- // Log error and continue.
- App.SetTrayIconUpdateError(e);
- }
- }
+ // There's a chance that a COMException can be thrown when rendering the bitmap.
+ // Catch any COM exceptions here and retry a few times then fail silently.
+ DelegateExtensions.RetryOnException(() => renderTargetBitmap.Render(textBlock),
+ App.SetTrayIconUpdateError);
- internal static void SetBatteryFullIcon(this NotifyIcon notifyIcon)
- {
- notifyIcon.SetIcon(new TextBlock
- {
- Text = "\uf5fc",
- Foreground = BrushExtensions.GetBatteryNormalBrush(),
- FontFamily = new FontFamily("Segoe Fluent Icons"),
- FontSize = 16
- });
+ // There's a chance that some native exception may be thrown when setting the icon's image.
+ // Catch any exception here and retry a few times then fail silently.
+ DelegateExtensions.RetryOnException(() => notifyIcon.Icon = renderTargetBitmap,
+ App.SetTrayIconUpdateError);
}
}
\ No newline at end of file
diff --git a/Pack/Package.appxmanifest b/Pack/Package.appxmanifest
index 6853644..ac42f11 100644
--- a/Pack/Package.appxmanifest
+++ b/Pack/Package.appxmanifest
@@ -12,7 +12,7 @@
+ Version="2.1.5.0" />
Battery Percentage Icon