Skip to content

Fix Form with StartPosition=CenterParent and WindowState=Maximized opening on wrong monitor#14156

Open
LeafShi1 wants to merge 3 commits intodotnet:mainfrom
LeafShi1:Fix_8932_Set_s_propDialogOwner_before_CreateControl
Open

Fix Form with StartPosition=CenterParent and WindowState=Maximized opening on wrong monitor#14156
LeafShi1 wants to merge 3 commits intodotnet:mainfrom
LeafShi1:Fix_8932_Set_s_propDialogOwner_before_CreateControl

Conversation

@LeafShi1
Copy link
Copy Markdown
Member

@LeafShi1 LeafShi1 commented Dec 22, 2025

Fixes #8932

Root Cause:

In the ShowDialog method, the s_propDialogOwner property was set after CreateControl() was called. This meant that during window creation, when FillInCreateParamsStartPosition is invoked to determine window coordinates, the dialog owner information was not yet available. As a result, the window coordinates defaulted to the primary monitor, and Windows would maximize the form on that monitor regardless of where the parent form was located.

Proposed changes

  • Move the Properties.AddOrRemoveValue(s_propDialogOwner, owner) call to before CreateControl() in the ShowDialog method
  • Remove the duplicate Properties.AddOrRemoveValue(s_propDialogOwner, owner) call that occurred after CreateControl()
  • This allows FillInCreateParamsStartPosition to access the dialog owner information during the CenterScreen positioning logic, which already has code to detect the owner's screen and position the window accordingly

Customer Impact

  • Forms with StartPosition=CenterParent and WindowState=Maximized will now correctly maximize on the same monitor as their owner/parent form

Regression?

  • Yes

Risk

  • Minimal (The change only affects the timing of when s_propDialogOwner is set in Properties dictionary, does not affect the Windows API parent-child relationship)

Screenshots

Before

In the form with value FormWindowState.Maximized it is always displayed on the main monitor.

After

A maximized window is displayed on the monitor where its parent window is located (i.e., the secondary monitor).

AfterChanges.mp4

Test methodology

  • Manually

Test environment(s)

  • .net 11.0.0-alpha.1.25617.103
Microsoft Reviewers: Open in CodeFlow

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

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 fixes an issue where modal forms with StartPosition=CenterParent and WindowState=Maximized would incorrectly open on the primary monitor instead of the same monitor as their parent form.

Key Changes:

  • Moved the s_propDialogOwner property assignment to occur before CreateControl() is called in the ShowDialog method
  • Removed the duplicate property assignment that previously occurred after CreateControl()

@codecov
Copy link
Copy Markdown

codecov Bot commented Dec 22, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 77.15252%. Comparing base (01eefd4) to head (4347fc0).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@                 Coverage Diff                 @@
##                main      #14156         +/-   ##
===================================================
+ Coverage   77.15180%   77.15252%   +0.00072%     
===================================================
  Files           3279        3279                 
  Lines         645333      645336          +3     
  Branches       47720       47721          +1     
===================================================
+ Hits          497886      497893          +7     
- Misses        143754      143759          +5     
+ Partials        3693        3684          -9     
Flag Coverage Δ
Debug 77.15252% <100.00000%> (+0.00072%) ⬆️
integration 18.98369% <100.00000%> (+0.00362%) ⬆️
production 52.01596% <100.00000%> (+0.00189%) ⬆️
test 97.40559% <ø> (ø)
unit 49.43428% <100.00000%> (-0.03317%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

SimonZhao888
SimonZhao888 previously approved these changes Dec 23, 2025
@KlausLoeffelmann
Copy link
Copy Markdown
Member

Hi, a couple of observations on this change:

1. Stale comment contradicts new behavior (Form.cs, ~line 5750): The existing comment explicitly states: "it is necessary to not set the owner before creating the handle. Otherwise, the window may never receive Dpi changed event even if its parent has different Dpi." — Your change now sets s_propDialogOwner via Properties.AddOrRemoveValue() before CreateControl(), directly contradicting this comment. If the DPI concern only applies to the Win32 owner relationship (set via Owner = form, which still happens after CreateControl), please update the comment to clarify the distinction: the property-bag entry for positioning is safe to set early, while the actual Win32 ownership must remain after handle creation.

2. DPI regression risk: The original ordering was deliberately chosen to ensure DPI-changed events fire correctly in multi-DPI setups (per the comment above). While your PR description correctly notes this only affects the property dictionary and not the Win32 parent-child relationship, it would be prudent to verify on a multi-monitor setup with different DPI settings that DPI-changed events still fire as expected for maximized dialogs shown via ShowDialog.

(Copilot co-authored on Klaus' behalf.)

Updated comments to clarify DPI handling in multi-DPI environments.
@LeafShi1
Copy link
Copy Markdown
Member Author

LeafShi1 commented Apr 1, 2026

Hi, a couple of observations on this change:

1. Stale comment contradicts new behavior (Form.cs, ~line 5750): The existing comment explicitly states: "it is necessary to not set the owner before creating the handle. Otherwise, the window may never receive Dpi changed event even if its parent has different Dpi." — Your change now sets s_propDialogOwner via Properties.AddOrRemoveValue() before CreateControl(), directly contradicting this comment. If the DPI concern only applies to the Win32 owner relationship (set via Owner = form, which still happens after CreateControl), please update the comment to clarify the distinction: the property-bag entry for positioning is safe to set early, while the actual Win32 ownership must remain after handle creation.

2. DPI regression risk: The original ordering was deliberately chosen to ensure DPI-changed events fire correctly in multi-DPI setups (per the comment above). While your PR description correctly notes this only affects the property dictionary and not the Win32 parent-child relationship, it would be prudent to verify on a multi-monitor setup with different DPI settings that DPI-changed events still fire as expected for maximized dialogs shown via ShowDialog.

(Copilot co-authored on Klaus' behalf.)

@KlausLoeffelmann For issue1: I updated the comment
For issue2: The change only moves the assignment of the logical dialog owner into the property bag (s_propDialogOwner) before CreateControl(). The actual Win32 owner (HWND owner) continues to be assigned after the handle has been created, in the same place and order as before this PR. This means the original DPI-related concern in the comment still applies to the HWND owner ordering, but is not affected by the property-bag update.

@LeafShi1 LeafShi1 added the waiting-review This item is waiting on review by one or more members of team label Apr 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

needs-area-label waiting-review This item is waiting on review by one or more members of team

Projects

None yet

4 participants