[英]How do I compute the non-client window size in WPF?
WPF 具有公開大量系統指標的SystemParameters
類。 在我的計算機上,我注意到一個普通窗口的標題高 30 像素,邊框寬 8 像素。 這是在啟用 Aero 主題的 Windows 7 上:
但是, SystemParameters
返回以下值:
SystemParameters.BorderWidth = 5
SystemParameters.CaptionHeight = 21
在這里,我禁用了 Aero 主題:
現在, SystemParameters
返回以下值:
SystemParameters.BorderWidth = 1
SystemParameters.CaptionHeight = 18
如何使用SystemParameters
計算實際觀察值?
對於可調整大小的窗口,您需要使用一組不同的參數來計算大小:
var titleHeight = SystemParameters.WindowCaptionHeight
+ SystemParameters.ResizeFrameHorizontalBorderHeight;
var verticalBorderWidth = SystemParameters.ResizeFrameVerticalBorderWidth;
當您修改主題時,這些尺寸會發生變化。
我很確定GetSystemMetrics
函數( SystemParameters
類使用適當的參數在內部調用)正在為您的系統返回正確的值,它只是在 Aero 主題是否被禁用的情況下返回正確的值。 通過打開 Aero,你可以獲得更強大的邊框和更高的窗口標題,所有這些都是多汁的圖形優點。
如果您想獲得這些窗口元素的正確大小,無論用戶當前的主題如何(請記住,您可以使用 Classic 主題、Aero Basic 主題或完整的 Aero 主題運行 Windows Vista 及更高版本,所有這些都將要擁有不同大小的 UI 元素),您需要使用 Vista 及更高版本中可用的不同方法。
您需要向窗口發送WM_GETTITLEBARINFOEX
消息以請求擴展標題欄信息。 wParam
未使用,應為零。 lParam
包含一個指向TITLEBARINFOEX
結構的指針,該結構將接收所有信息。 調用者負責為此結構分配內存並設置其cbSize
成員。
要從 .NET 應用程序執行所有這些操作,您顯然需要執行一些 P/Invoke。 首先定義您需要的常量,以及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;
}
然后相應地定義SendMessage
函數:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
internal static extern IntPtr SendMessage(
IntPtr hWnd,
int uMsg,
IntPtr wParam,
ref TITLEBARINFOEX lParam);
最后,您可以使用以下代碼調用所有這些混亂:
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;
}
編輯:現在在我的運行 Windows 7 的筆記本上進行測試和工作。
請參閱以下內容:
我想您正在嘗試計算必須使應用程序窗口的大小,以便提供適量的客戶區以完全顯示某些 WPF 內容?
如果是這樣,那么請記住 WPF 的像素為 96dpi,並且您的顯示器可能以不同的 dpi 運行……正如其他答案所述,主題會影響您必須調整主窗口的大小以獲得所需的大小客戶區。
或者,您可以在 Window 的子控件上使用 MinWidth/MinHeight。
這是一個 C++/CLI 答案,它沒有使用SystemParameters
,但我認為這是解決這個問題的更好方法,因為它應該適用於任何窗口。
事實上,其他答案僅對可調整大小的窗口有效,並且必須為每個可用的WindowStyle
創建不同的案例。
由於這些計算所需的每個SystemParameters
都有一個記錄在案的 SM_CX* 或 SM_CY* 值,我認為與其重新發明輪子, AdjustWindowRectEx
簡單地使用 WinAPI AdjustWindowRectEx
函數。
bool SetWindowClientArea(System::Windows::Window^ win, int width, int height) {
System::Windows::Interop::WindowInteropHelper^ wi = gcnew System::Windows::Interop::WindowInteropHelper(win);
wi->EnsureHandle();
HWND win_HWND = (HWND)(wi->Handle.ToPointer());
LONG winStyle = GetWindowLong(win_HWND, GWL_STYLE);
LONG winExStyle = GetWindowLong(win_HWND, GWL_EXSTYLE);
RECT r = { 0 };
r.right = width;
r.bottom = height;
BOOL bres = AdjustWindowRectEx(&r, winStyle, FALSE, winExStyle);
if (bres) {
Double w = r.right - r.left;
Double h = r.bottom - r.top;
win->Width = w;
win->Height = h;
}
return bres;
}
可以使用更多的DllImport
輕松將上述代碼轉換為 C#,或者如果您的項目已經在使用,則可以將其放入 C++/CLI 程序集。
對於重新調整大小的窗口
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;
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.