c # - Hvordan beregner jeg vinduets størrelse i WPF?

Indlæg af Hanne Mølgaard Plasc

Problem



WPF har klassen SystemParameters, som udsætter et stort antal systemmålinger. På min computer har jeg bemærket, at et normalt vindue har en titel, der er 30 pixels høj og en kant der er 8 pixel bred. Dette er på Windows 7 med Aero-temaet aktiveret: [21]


Ikke-klient område - Aero


Men SystemParameters returnerer følgende værdier:


SystemParameters.BorderWidth = 5
SystemParameters.CaptionHeight = 21


Her har jeg deaktiveret Aero-temaet:


Ikke-klientområde - klassisk


Nu, SystemParameters returnerer følgende værdier:


SystemParameters.BorderWidth = 1
SystemParameters.CaptionHeight = 18


Hvordan beregner jeg de faktiske observerede værdier ved at bruge SystemParameters?

Bedste reference


For et resizable vindue skal du bruge et andet sæt parametre til at beregne størrelsen:


var titleHeight = SystemParameters.WindowCaptionHeight
  + SystemParameters.ResizeFrameHorizontalBorderHeight;
var verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth;


Disse størrelser ændres, når du ændrer temaet.

Andre referencer 1


Jeg er ganske sikker på, at funktionen GetSystemMetrics (som klassen SystemParameters kalder internt med de relevante argumenter) er returnerer de korrekte værdier for dit system, det vender bare tilbage De korrekte værdier i tilfælde af, om Aero-temaet er deaktiveret. Ved at tænde på Aero får du kædere grænser og højere vinduesskilt, alt det saftige grafiske godhed. [22]


Hvis du vil have den rigtige størrelse af disse vindueselementer, uanset brugerens aktuelle tema (husk, du kan køre Windows Vista og videre med Classic-temaet, Aero Basic-temaet eller hele Aero-temaet, som alle skal have forskellige UI-elementer), skal du bruge en anden metode, der er tilgængelig i Vista og senere.


Du skal sende vinduet en WM\_GETTITLEBARINFOEX besked for at anmode om udvidet titellinjeinformation. wParam er ubrugt og bør være nul. lParam indeholder en pointer til en TITLEBARINFOEX struktur, som vil modtage al informationen. Opkalderen er ansvarlig for at allokere hukommelse til denne struktur og indstille sin cbSize medlem. [23] [24]


For at gøre alt dette fra en .NET-applikation, skal du naturligvis gøre nogle P/Invoke. Begynd med at definere de konstanter, du har brug for, samt strukturen TITLEBARINFOEX:


internal const int WM\_GETTITLEBARINFOEX = 0x033F;
internal const int CCHILDREN\_TITLEBAR = 5;

[StructLayout(LayoutKind.Sequential)]
internal struct TITLEBARINFOEX
{
    public int cbSize;
    public Rectangle rcTitleBar;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN\_TITLEBAR + 1)]
    public int[] rgstate;
    [MarshalAs(UnmanagedType.ByValArray, SizeConst = CCHILDREN\_TITLEBAR + 1)]
    public Rectangle[] rgrect;
}


Definer derefter funktionen SendMessage i overensstemmelse hermed:


[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(
                                          IntPtr hWnd,
                                          int uMsg,
                                          IntPtr wParam,
                                          ref TITLEBARINFOEX lParam);


Og endelig kan du kalde alt det rod, der bruger noget som følgende kode:


internal static TITLEBARINFOEX GetTitleBarInfoEx(IntPtr hWnd)
{
    // Create and initialize the structure
    TITLEBARINFOEX tbi = new TITLEBARINFOEX();
    tbi.cbSize = Marshal.SizeOf(typeof(TITLEBARINFOEX));

    // Send the WM\_GETTITLEBARINFOEX message
    SendMessage(hWnd, WM\_GETTITLEBARINFOEX, IntPtr.Zero, ref tbi);

    // Return the filled-in structure
    return tbi;
}


EDIT: Nu testet og arbejder på min notesbog, der kører Windows 7.

Andre referencer 2


Se følgende:


http://blogs.microsoft.co.il/blogs/alex\_golesh/archive/2009/09/20/wpf-quick-tip-how-to-get-wpf-window-client-area-size.aspx[25]


Jeg formoder, at du forsøger at beregne størrelsen, du skal gøre på Applikationsvinduet for at give det rigtige antal klientområde for fuldt ud at vise noget WPF-indhold?


Hvis det er tilfældet, så husk bare, at WPFs pixel er 96dpi, og din skærm kan køre med en anden dpi ... også som nævnt af andre svar, påvirker temaet, hvor stort du skal have dit hovedvindue for at få det dit ønskede klientområde.


Alternativt kan du muligvis bruge MinWidth/MinHeight på barnets kontrol af vinduet.

Andre referencer 3


Til re-sizable vindue


NON\_CLIENT\_AREA\_HEIGHT = SystemParameters.WindowNonClientFrameThickness.Top +
                SystemParameters.WindowNonClientFrameThickness.Bottom +
                SystemParameters.WindowResizeBorderThickness.Top +
                SystemParameters.WindowResizeBorderThickness.Bottom;

            NON\_CLIENT\_AREA\_WIDTH = SystemParameters.WindowNonClientFrameThickness.Left +
                SystemParameters.WindowNonClientFrameThickness.Right +
                SystemParameters.WindowResizeBorderThickness.Left +
                SystemParameters.WindowResizeBorderThickness.Right;