Nach vielen Experimenten und Versuchen habe ich eine Lösung gefunden. Ich habe OnResize überschrieben und die Größe des Formulars an die ListBox darin angepasst (siehe meinen Kommentar zu John Saunders Antwort).
Wie ich in meiner Frage erwähnt habe, habe ich festgestellt, dass die Größe des Formulars nach dem Senden von WM_WINDOWPOSCHANGED zurückgeht. Weitere Untersuchungen ergaben, dass der Größenrückgang tatsächlich beginnt, wenn WM_WINDOWPOSCHANGING gesendet wird.
WM_WINDOWPOSCHANGING ist die Schwestermeldung von WM_WINDOWPOSCHANGED, die auftritt, bevor sich die Fenstergröße tatsächlich ändert. Ich weiß nicht, warum, aber aus irgendeinem Grund passt WM_WINDOWPOSCHANGING die Größe des Formulars blind an die vom Betriebssystem vorgegebenen Grenzen an (offenbar wird das Fenster nicht mit WM_GETMINMAXINFO abgefragt). So musste ich WM_WINDOWPOSCHANGING abfangen und überschreiben es mit der Größe, die ich wirklich wollte.
Das bedeutet, dass ich die Größe des Formulars nicht mehr mit OnResize anpasse, sondern dass ich die Größe des Formulars anpasse, wenn ich WM_WINDOWPOSCHANGING erhalte. Das ist sogar besser als OnResize, weil es kein damit verbundenes Flackern gibt, das auftritt, wenn die Größe geändert wird und dann wieder geändert wird, wenn die Größe während OnResize angepasst wird.
Außerdem ist es notwendig, WM_GETMINMAXINFO abzufangen und zu überschreiben, andernfalls nützt Ihnen auch das Abfangen von WM_WINDOWPOSCHANGING nichts.
using System.Runtime.InteropServices;
private const int WM_WINDOWPOSCHANGING = 0x0046;
private const int WM_GETMINMAXINFO = 0x0024;
protected override void WndProc(ref Message m)
{
if (m.Msg == WM_WINDOWPOSCHANGING)
{
WindowPos windowPos = (WindowPos)m.GetLParam(typeof(WindowPos));
// Make changes to windowPos
// Then marshal the changes back to the message
Marshal.StructureToPtr(windowPos, m.LParam, true);
}
base.WndProc(ref m);
// Make changes to WM_GETMINMAXINFO after it has been handled by the underlying
// WndProc, so we only need to repopulate the minimum size constraints
if (m.Msg == WM_GETMINMAXINFO)
{
MinMaxInfo minMaxInfo = (MinMaxInfo)m.GetLParam(typeof(MinMaxInfo));
minMaxInfo.ptMinTrackSize.x = this.MinimumSize.Width;
minMaxInfo.ptMinTrackSize.y = this.MinimumSize.Height;
Marshal.StructureToPtr(minMaxInfo, m.LParam, true);
}
}
struct WindowPos
{
public IntPtr hwnd;
public IntPtr hwndInsertAfter;
public int x;
public int y;
public int width;
public int height;
public uint flags;
}
struct POINT
{
public int x;
public int y;
}
struct MinMaxInfo
{
public POINT ptReserved;
public POINT ptMaxSize;
public POINT ptMaxPosition;
public POINT ptMinTrackSize;
public POINT ptMaxTrackSize;
}