Skip to content

Context Menus (Popup) are sometimes broken in High-DPI applications in .NET 4.8  #2088

Open
@vatsan-madhavan

Description

@vatsan-madhavan

microsoft/dotnet#1036 (comment)

After installing .NET 4.8 we have observed that Context menus via the Popup class show strange effects.

  1. Popup is placed at top left corner
  2. Popup comes up empty
  3. Popup has no styles applied
  4. Alternating behavior:
    a) Popup works.
    b) Popup comes up empty
    ....

I have debugged that issue and found that the is Popup is sometimes destroyed while the popup window is meant to be created:

The diff from .NET 4.7.2 to 4.8 shows this new code was added:

image

This leads to the call stack that the popup is killed while it is beeing created:

0:000> !ClrStack
OS Thread Id: 0x2180 (0)
Call Site
System.Windows.Controls.Primitives.Popup.DestroyWindow()
System.Windows.Controls.Primitives.Popup.CreateWindow(Boolean)

System.Windows.Controls.Primitives.Popup.OnIsOpenChanged(System.Windows.DependencyObject, System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.DependencyObject.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.FrameworkElement.OnPropertyChanged(System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex, System.Windows.DependencyProperty, System.Windows.PropertyMetadata, System.Windows.EffectiveValueEntry, System.Windows.EffectiveValueEntry ByRef, Boolean, Boolean, System.Windows.OperationType)
System.Windows.DependencyObject.InvalidateProperty(System.Windows.DependencyProperty, Boolean)
System.Windows.Data.BindingExpressionBase.Invalidate(Boolean)
System.Windows.Data.BindingExpression.TransferValue(System.Object, Boolean)
MS.Internal.Data.ClrBindingWorker.NewValueAvailable(Boolean, Boolean, Boolean)
MS.Internal.Data.PropertyPathWorker.UpdateSourceValueState(Int32, System.ComponentModel.ICollectionView, System.Object, Boolean)
MS.Internal.Data.PropertyPathWorker.OnDependencyPropertyChanged(System.Windows.DependencyObject, System.Windows.DependencyProperty, Boolean)
System.Windows.Data.BindingExpression.HandlePropertyInvalidation(System.Windows.DependencyObject, System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.Data.BindingExpressionBase.OnPropertyInvalidation(System.Windows.DependencyObject, System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.Data.BindingExpression.OnPropertyInvalidation(System.Windows.DependencyObject, System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.DependentList.InvalidateDependents(System.Windows.DependencyObject, System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.DependencyObject.NotifyPropertyChange(System.Windows.DependencyPropertyChangedEventArgs)
System.Windows.DependencyObject.UpdateEffectiveValue(System.Windows.EntryIndex, System.Windows.DependencyProperty, System.Windows.PropertyMetadata, System.Windows.EffectiveValueEntry, System.Windows.EffectiveValueEntry ByRef, Boolean, Boolean, System.Windows.OperationType)
System.Windows.DependencyObject.SetValueCommon(System.Windows.DependencyProperty, System.Object, System.Windows.PropertyMetadata, Boolean, Boolean, System.Windows.OperationType, Boolean)
System.Windows.DependencyObject.SetCurrentValueInternal(System.Windows.DependencyProperty, System.Object)

System.Windows.Controls.PopupControlService.**RaiseContextMenuOpeningEvent**(System.Windows.IInputElement, Double, Double, Boolean)

System.Windows.Controls.PopupControlService.ProcessMouseUp(System.Object, System.Windows.Input.MouseButtonEventArgs)
System.Windows.Controls.PopupControlService.OnPostProcessInput(System.Object, System.Windows.Input.ProcessInputEventArgs)
System.Windows.Input.InputManager.RaiseProcessInputEventHandlers(System.Windows.Input.ProcessInputEventHandler, System.Windows.Input.ProcessInputEventArgs)
System.Windows.Input.InputManager.ProcessStagingArea()
System.Windows.Input.InputManager.ProcessInput(System.Windows.Input.InputEventArgs)
System.Windows.Input.InputProviderSite.ReportInput(System.Windows.Input.InputReport)
System.Windows.Interop.HwndMouseInputProvider.ReportInput(IntPtr, System.Windows.Input.InputMode, Int32, System.Windows.Input.RawMouseActions, Int32, Int32, Int32)
System.Windows.Interop.HwndMouseInputProvider.FilterMessage(IntPtr, MS.Internal.Interop.WindowMessage, IntPtr, IntPtr, Boolean ByRef)
System.Windows.Interop.HwndSource.InputFilterMessage(IntPtr, Int32, IntPtr, IntPtr, Boolean ByRef)

To me this looks like an error. The window should not be killed when it is already (partially) active. This call should therefore be moved to the check where BuildWindow is beeing called.
After setting the AppContext switch

  <runtime>
    <AppContextSwitchOverrides value="Switch.System.Windows.DoNotScaleForDpiChanges=true" />
  </runtime>

the issue does go away. This has therefore something to do with the monitor scaling flag during Popup.CreateWindow.

Metadata

Metadata

Assignees

No one assigned

    Labels

    .NET FrameworkBugProduct bug (most likely)issue-type-netfx-portPorts from .NET Frameworkregressionstatus: This issue is a regression from a previous build or releasetenet-reliabilityReliability related issue

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions