Is it just my delphi applications that behave poorly when handling dpi changes? This is when setting high dpi in the manifest to PerMonitorV2. I have verified that the controls (many of them mine) are handling this as they should (override ChangeScale).
When dragging the application between monitors with different dpi's, it takes 3-4 seconds while the window flickers and repaints multiple times - the dragging operation pauses while it does this, and then the window eventually jumps to where you actually dragged it.
I've been looking at other applications (that ssupport PerMonitorV2) to see how they behave, even explorer stutters a little, due I guess to the ribbon control - but the stutter is around the 200ms mark. Thunderbird seem to repaint twice but very fast.
After some debugging, as far as I can tell, this is caused by all controls getting their ChangeScale method called (as you would expect) which results in calls to SetBounds, which invalidates the control causing more painting!
TWinControl.ScaleControlsForDpi appears to be doing the right thing (control alignment is a perf hog), but calling EnableAlign inevitably invalidates the control, again.
procedure TWinControl.ScaleControlsForDpi(NewPPI: Integer);
var
I: Integer;
begin
DisableAlign;
try
for I := 0 to ControlCount - 1 do
Controls[I].ScaleForPPI(NewPPI);
finally
EnableAlign;
end;
end;
This really show up an inherent design flaw in the vcl, there is no BeginUpdate/EndUpdate design pattern in the vcl that allows a control (or form) to disable child controls painting until it's done. Many controls implement this pattern individually, but that doesn't help in this scenario.
The situation isn't helped by my using Vcl Themes either - resize (setbounds) causes serious flicker in some controls and I'm sure this is coming into play here too.
I tried to fudge a BeginUpdate/EndUpdate with this :
procedure TMainForm.WMDpiChanged(var Message: TWMDpi);
begin
SendMessage(Self.Handle, WM_SETREDRAW, NativeUInt(False), 0);
try
inherited;
finally
SendMessage(Self.Handle, WM_SETREDRAW, NativeUInt(true), 0);
RedrawWindow(Self.Handle, nil, 0, RDW_INVALIDATE or RDW_UPDATENOW or RDW_ALLCHILDREN);
end;
end;
It cut's out the visible repainting, but doesn't speed things up much
If anyone has any ideas on how to tackle this I'm all ears.