Compare commits

..

2 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
466bd0c0a5 Fix: subscribe to ItemsChanged before fetching items to avoid missing early events
Agent-Logs-Url: https://github.com/microsoft/PowerToys/sessions/3f380bd3-a56a-4708-80ef-3e7d534c4f6f

Co-authored-by: MuyuanMS <116717757+MuyuanMS@users.noreply.github.com>
2026-04-29 08:58:21 +00:00
copilot-swe-agent[bot]
8db30b7e46 Initial plan 2026-04-29 08:49:46 +00:00
5 changed files with 4 additions and 72 deletions

View File

@@ -129,8 +129,8 @@ public partial class ContentPageViewModel : PageViewModel, ICommandBarContext
UpdateDetails();
FetchContent();
model.ItemsChanged += Model_ItemsChanged;
FetchContent();
DoOnUiThread(
() =>

View File

@@ -44,9 +44,9 @@ public partial class ContentTreeViewModel(ITreeContent _tree, WeakReference<IPag
UpdateProperty(nameof(Root));
}
FetchContent();
model.PropChanged += Model_PropChanged;
model.ItemsChanged += Model_ItemsChanged;
FetchContent();
}
// Theoretically, we should unify this with the one in CommandPalettePageViewModelFactory

View File

@@ -209,8 +209,8 @@ public sealed partial class DockBandViewModel : ExtensionObjectViewModel
var list = command.Model.Unsafe as IListPage;
if (list is not null)
{
InitializeFromList(list);
list.ItemsChanged += HandleItemsChanged;
InitializeFromList(list);
}
else
{

View File

@@ -957,8 +957,8 @@ public partial class ListViewModel : PageViewModel, IDisposable
Filters?.InitializeProperties();
UpdateProperty(nameof(Filters));
FetchItems(true);
model.ItemsChanged += Model_ItemsChanged;
FetchItems(true);
}
private static IGridPropertiesViewModel? LoadGridPropertiesViewModel(IGridProperties? gridProperties)

View File

@@ -3,7 +3,6 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Diagnostics;
using System.Windows;
using System.Windows.Threading;
@@ -67,79 +66,12 @@ namespace PowerLauncher.Helper
var logger = LogManager.GetLogger(LoggerName);
logger.Error($"From {(isNotUIThread ? "non" : string.Empty)} UI thread's exception: {ExceptionFormatter.FormatException(e)}");
}
else if (IsExceptionFromUserPlugin(e))
{
// Exceptions thrown by user-installed third-party plugins should be logged
// but must not show the crash report window, since the exception is not
// caused by PowerToys itself and the popup is confusing and alarming to the user.
var logger = LogManager.GetLogger(LoggerName);
logger.Error($"From {(isNotUIThread ? "non" : string.Empty)} UI thread - Exception from user plugin: {ExceptionFormatter.FormatException(e)}");
}
else
{
Report(e, isNotUIThread);
}
}
/// <summary>
/// Determines whether an exception originated from a user-installed third-party plugin
/// (i.e., an assembly loaded from <see cref="Constant.PluginsDirectory"/>).
/// </summary>
private static bool IsExceptionFromUserPlugin(Exception e)
{
var current = e;
while (current != null)
{
if (HasPluginStackFrames(current))
{
return true;
}
if (current is AggregateException aggregateException)
{
foreach (var innerException in aggregateException.InnerExceptions)
{
if (IsExceptionFromUserPlugin(innerException))
{
return true;
}
}
}
current = current.InnerException;
}
return false;
}
private static bool HasPluginStackFrames(Exception e)
{
try
{
var pluginsDir = Constant.PluginsDirectory;
var stackTrace = new StackTrace(e, fNeedFileInfo: false);
foreach (var frame in stackTrace.GetFrames() ?? [])
{
var assemblyLocation = frame.GetMethod()?.DeclaringType?.Assembly?.Location;
if (!string.IsNullOrEmpty(assemblyLocation) &&
assemblyLocation.StartsWith(pluginsDir, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
}
catch (System.Exception)
{
// Reflection-based stack inspection can throw a variety of exceptions
// (e.g., SecurityException, TypeLoadException, BadImageFormatException).
// In every failure case the safe fallback is to treat the exception as
// NOT originating from a plugin so that it still surfaces as a crash report.
}
return false;
}
private static void Report(Exception e, bool waitForClose)
{
if (e != null)