Skip to content

Fix bug #1016 - #1027

Merged
vb2ae merged 3 commits into
Caliburn-Micro:masterfrom
508159280:master
Nov 10, 2025
Merged

Fix bug #1016#1027
vb2ae merged 3 commits into
Caliburn-Micro:masterfrom
508159280:master

Conversation

@LIJIAOLONG96

Copy link
Copy Markdown
Contributor

No description provided.

@vb2ae
vb2ae requested a review from Copilot November 6, 2025 12:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for handling popup scenarios in Avalonia by implementing visual tree traversal through PopupRoot elements and adds a guard to prevent execution of actions on controls that are not yet loaded.

  • Added an early return in TriggerAction.Execute() when the control is not loaded
  • Modified visual parent traversal logic to handle PopupRoot elements by traversing through the Popup's PlacementTarget

Reviewed Changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 4 comments.

File Description
src/Caliburn.Micro.Platform/Platforms/netcore-avalonia/TriggerAction.cs Adds IsLoaded check to prevent execution of actions before control is loaded
src/Caliburn.Micro.Platform/ActionMessage.cs Adds PopupRoot handling logic to traverse visual tree through popups and imports Avalonia.Controls.Primitives namespace

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

AssociatedObject = (Control)sender;
}

if (!AssociatedObject.IsLoaded)

Copilot AI Nov 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential null reference exception if AssociatedObject is null. The check at line 57-60 only sets AssociatedObject when sender is a Control, but doesn't guarantee AssociatedObject is non-null. Add a null check before accessing AssociatedObject.IsLoaded.

Suggested change
if (!AssociatedObject.IsLoaded)
if (AssociatedObject == null || !AssociatedObject.IsLoaded)

Copilot uses AI. Check for mistakes.
//Modified parts Begin
var pElement = BindingScope.GetVisualParent(currentElement);
if (pElement == null
&& currentElement.GetType().Name.Equals("PopupRoot", StringComparison.OrdinalIgnoreCase))

Copilot AI Nov 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using string comparison with GetType().Name is fragile and should be avoided. Use 'is PopupRoot' type checking instead, which is safer and more maintainable. If PopupRoot might not be accessible at compile time, consider using 'as PopupRoot' pattern.

Suggested change
&& currentElement.GetType().Name.Equals("PopupRoot", StringComparison.OrdinalIgnoreCase))
&& currentElement is PopupRoot)

Copilot uses AI. Check for mistakes.
Comment on lines +600 to +602
//currentElement = BindingScope.GetVisualParent(currentElement);

//Modified parts Begin

Copilot AI Nov 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove commented-out code and temporary development comments ('Modified parts Begin' and 'End'). These comments add no value and reduce code readability.

Copilot uses AI. Check for mistakes.
Comment on lines +605 to +610
&& currentElement.GetType().Name.Equals("PopupRoot", StringComparison.OrdinalIgnoreCase))
{
if (currentElement is PopupRoot popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}

Copilot AI Nov 6, 2025

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 'if' statements can be combined.

Suggested change
&& currentElement.GetType().Name.Equals("PopupRoot", StringComparison.OrdinalIgnoreCase))
{
if (currentElement is PopupRoot popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}
&& currentElement.GetType().Name.Equals("PopupRoot", StringComparison.OrdinalIgnoreCase)
&& currentElement is PopupRoot popupRoot
&& popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;

Copilot uses AI. Check for mistakes.
@vb2ae

vb2ae commented Nov 6, 2025

Copy link
Copy Markdown
Member

@869570967 thank you so much for this. Could you please look at this error when building the code in your branch?

error CS0246: The type or namespace name 'PopupRoot' could not be found (are you missing a using directive or an assembly reference?) [D:\a\Caliburn.Micro\Caliburn.Micro\src\Caliburn.Micro.WinUI3\Caliburn.Micro.WinUI3.csproj]

@LIJIAOLONG96

Copy link
Copy Markdown
Contributor Author

I am very sorry, I didn't consider the situation outside of Avalonia. PopupRoot is accessible in Avalonia, but it is not accessible in WPF, so I made some adjustments here. @vb2ae

@LIJIAOLONG96

Copy link
Copy Markdown
Contributor Author

The code has been submitted, but I didn't see this morning's push entry. Is it the case that after the first push, subsequent pushes will be automatically sent to you for review and merging? @vb2ae

@LIJIAOLONG96

Copy link
Copy Markdown
Contributor Author

@vb2ae Excluding UWP compilation, I have not developed for UWP and do not know if there are popups on UWP. If you want to fix such issues on UWP, you will need to handle it yourself.

@vb2ae

vb2ae commented Nov 6, 2025

Copy link
Copy Markdown
Member

@869570967 thanks. UWP does have a up

Comment on lines +604 to +620
if (pElement == null
&& currentElement.GetType().Name.Equals("PopupRoot", StringComparison.OrdinalIgnoreCase))
{

#if AVALONIA
if (currentElement is PopupRoot popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}

#elif !WINDOWS_UWP
if (currentElement is FrameworkElement popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}
#endif
}

Check warning

Code scanning / CodeQL

Futile conditional Warning

If-statement with an empty then-branch and no else-branch.
Comment on lines +606 to +620
{

#if AVALONIA
if (currentElement is PopupRoot popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}

#elif !WINDOWS_UWP
if (currentElement is FrameworkElement popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}
#endif
}

Check warning

Code scanning / CodeQL

Empty branch of conditional, or empty loop body Warning

Empty block without comment.
Comment on lines +604 to +620
if (pElement == null
&& currentElement.GetType().Name.Equals("PopupRoot", StringComparison.OrdinalIgnoreCase))
{

#if AVALONIA
if (currentElement is PopupRoot popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}

#elif !WINDOWS_UWP
if (currentElement is FrameworkElement popupRoot && popupRoot.Parent is Popup popup)
{
pElement = popup.PlacementTarget;
}
#endif
}

Check notice

Code scanning / CodeQL

Nested 'if' statements can be combined Note

These 'if' statements can be combined.
@vb2ae

vb2ae commented Nov 10, 2025

Copy link
Copy Markdown
Member

I merged this in. Want to add a page to the features sample with a popup before I push it to nuget. You can download use the MyGet version of the package in a little while. https://www.myget.org/feed/caliburn-micro-builds/package/nuget/Caliburn.Micro.avalonia

@vb2ae
vb2ae merged commit 6a440a4 into Caliburn-Micro:master Nov 10, 2025
4 checks passed
@LIJIAOLONG96

Copy link
Copy Markdown
Contributor Author

@vb2ae Thank you

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants