[英]C# WPF create dpi aware child window
我想在 WPF 窗口內創建一個 dpi 感知子窗口。 子窗口將用於 DirectX 渲染。
我創建了一個帶有窗口的最小示例,如下所示:
<Window ...
Loaded="OnLoaded"
MouseMove="MainWindow_OnMouseMove">
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="TestItem"/>
</Menu>
<Border Background="Blue" x:Name="BorderHost"/>
</DockPanel>
</Window>
Border 將用於托管我的子窗口。 邊界的HwndHost
創建HwndHost
交換鏈,如下所示:
public class ChildWindow : HwndHost
{
private readonly Border parent;
private IntPtr hWnd = IntPtr.Zero;
public SwapChain SwapChain { get; private set; }
public ChildWindow(Border parent)
{
this.parent = parent;
parent.SizeChanged += ParentOnSizeChanged;
}
private void ParentOnSizeChanged(object sender, SizeChangedEventArgs e)
{
// problem: width and height is not correctly scaled
SwapChain?.Resize((int)(parent.ActualWidth), (int)(parent.ActualHeight));
}
protected override HandleRef BuildWindowCore(HandleRef hwndParent)
{
// create subwindow
hWnd = CreateWindowEx(
0, // dwstyle
"static", // class name
"", // window name
WS_CHILD | WS_VISIBLE, // style
0, // x
0, // y
(int)parent.ActualWidth, // renderWidth
(int)parent.ActualHeight, // renderHeight
hwndParent.Handle, // parent handle
IntPtr.Zero, // menu
IntPtr.Zero, // hInstance
0 // param
);
// directx swap chain
// problem: width and height is not correctly scaled
SwapChain = new SwapChain(hWnd, (int)parent.ActualWidth, (int)parent.ActualHeight);
return new HandleRef(this, hWnd);
}
protected override void DestroyWindowCore(HandleRef hwnd)
{
DestroyWindow(hWnd);
}
[DllImport("user32.dll", EntryPoint = "DestroyWindow", CharSet = CharSet.Unicode)]
internal static extern bool DestroyWindow(IntPtr hwnd);
[DllImport("user32.dll", EntryPoint = "CreateWindowEx", CharSet = CharSet.Unicode)]
internal static extern IntPtr CreateWindowEx(
int dwExStyle,
string lpszClassName,
string lpszWindowName,
int style,
int x, int y,
int width, int height,
IntPtr hwndParent,
IntPtr hMenu,
IntPtr hInst,
[MarshalAs(UnmanagedType.AsAny)] object pvParam
);
internal const int
WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000;
}
主窗口初始化子窗口並在鼠標移動后將其背景清除為黑色或白色:
public partial class MainWindow : Window
{
private ChildWindow child;
private float childColor = 1.0f;
public MainWindow()
{
InitializeComponent();
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
child = new ChildWindow(BorderHost);
BorderHost.Child = child;
}
private void MainWindow_OnMouseMove(object sender, MouseEventArgs e)
{
if (child == null) return;
if (child.SwapChain == null) return;
// switch between black and white background
childColor = 1.0f - childColor;
// clear child background
child.SwapChain.BeginFrame();
Device.Get().ClearRenderTargetView(child.SwapChain.Rtv, new RawColor4(childColor, childColor, childColor, childColor));
child.SwapChain.EndFrame();
}
}
完整的源代碼可以在https://github.com/kopaka1822/DpiAwareChildwindow上找到。
筆記:
為了向我的應用程序添加 dpi 感知,我添加了一個清單:
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">True/PM</dpiAware>
<gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">true</gdiScaling>
</windowsSettings>
</application>
我將gdiScaling
設置為 true,因為我希望窗口內的所有 WPF 組件都能像往常一樣縮放。
但是,使用 DPI 2.0 的顯示器上的子窗口位置和大小是錯誤的:
如何正確縮放和定位我的子窗口?
編輯:這就是我在清單中不使用 gdiScaling 縮放並將窗口從 2.0 dpi 移動到 1.0 dpi 屏幕時得到的結果: 該窗口在 2.0 dpi 屏幕上看起來不錯,但我的窗口的標題欄現在在 1.0 dpi 屏幕上過大。
根據文檔,我將gdiScaling
修改為以下格式,它對我gdiScaling
。
<application xmlns="urn:schemas-microsoft-com:asm.v3">
<windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true/pm</dpiAware>
<!--<gdiScaling xmlns="http://schemas.microsoft.com/SMI/2017/WindowsSettings">true</gdiScaling>-->
</windowsSettings>
</application>
<application>
<windowsSettings xmlns="https://schemas.microsoft.com/SMI/2017/WindowsSettings">
<gdiScaling>true</gdiScaling>
</windowsSettings>
</application>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.