Tôi đã suy nghĩ về điều này trong một vài ngày nhưng tôi nghĩ rằng tôi thiếu một số hiểu biết cơ bản về cách windows và wpf làm việc trong nội bộ để tìm ra điều này.Tùy chỉnh kích thước cửa sổ được vẽ trên các phần tử HwndHost
Vấn đề là thế này:
Tôi tạo ra một cửa sổ mà nên hãy để tôi vẽ điều khiển WPF trên thanh tiêu đề aero (như văn phòng). Điều này làm việc tốt miễn là tôi không thêm phần tử Hwndhost vào cửa sổ, trong trường hợp này bất cứ khi nào tôi thay đổi kích cỡ khung và HwndHost bắt đầu nhấp nháy khá nặng (các yếu tố khác có vẻ hiển thị chính xác). Tôi cũng đã thử sử dụng triển khai khung cửa sổ tùy chỉnh từ WPF Shell Integration library và kết quả là như nhau, vì vậy tôi nghĩ rằng đó không hoàn toàn là lỗi của tôi.
Mã sau đây là một chương trình đơn giản có thể biên dịch được để tái tạo sự cố. Mẫu thử trong C# nhưng câu trả lời không nhất thiết phải như vậy.
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Interop;
using System.Windows.Media;
using System.Windows.Threading;
namespace DwmTest {
class Program {
[STAThread]
static void Main() {
var w = new CustomFrameWindow{ Content = new WindowHost() };
w.Show();
((Border)VisualTreeHelper.GetChild(w, 0)).Margin = new Thickness(11, 33, 11, 11);
Dispatcher.Run();
}
}
public class CustomFrameWindow : Window {
const int resizeFrameWidth = 11;
const int captionHeight = 33;
public enum HT { CLIENT = 1, CAPTION = 2, LEFT = 10, RIGHT, TOP, TOPLEFT, TOPRIGHT, BOTTOM, BOTTOMLEFT, BOTTOMRIGHT }
[StructLayout(LayoutKind.Sequential)]
public struct Margins { public int left, right, top, bottom; }
[DllImport("user32.dll")]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int x, int y, int cx, int cy, int flags);
[DllImport("dwmapi.dll")]
public static extern bool DwmDefWindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, out IntPtr result);
[DllImport("dwmapi.dll", PreserveSig = false)]
public static extern void DwmExtendFrameIntoClientArea(IntPtr hwnd, ref Margins pMarInset);
protected override void OnSourceInitialized(EventArgs e) {
base.OnSourceInitialized(e);
var hWndSource = HwndSource.FromHwnd(new WindowInteropHelper(this).Handle);
hWndSource.CompositionTarget.BackgroundColor = Colors.Transparent;
var nonClientArea = new Margins{
left = resizeFrameWidth, top = captionHeight, bottom = resizeFrameWidth, right = resizeFrameWidth
};
DwmExtendFrameIntoClientArea(hWndSource.Handle, ref nonClientArea);
hWndSource.AddHook(WndProc);
// FRAMECHANGED | NOMOVE | NOSIZE
SetWindowPos(hWndSource.Handle, new IntPtr(), 0, 0, 0, 0, 0x0020 | 0x0002 | 0x0001);
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) {
switch(msg) {
case 0x0083: // NCCALCSIZE
if(wParam != IntPtr.Zero) handled = true;
break;
case 0x0084: // NCHITTEST
handled = true;
IntPtr dwmHitTest;
if(DwmDefWindowProc(hwnd, msg, wParam, lParam, out dwmHitTest)) {
return dwmHitTest;
}
var mousePosition = PointFromScreen(new Point(lParam.ToInt32() & 0xFFFF, lParam.ToInt32() >> 16));
var isTop = mousePosition.Y <= resizeFrameWidth;
var isBottom = mousePosition.Y >= ActualHeight - resizeFrameWidth;
var isLeft = mousePosition.X <= resizeFrameWidth;
var isRight = mousePosition.X >= ActualWidth - resizeFrameWidth;
var hitTest = HT.CLIENT;
if(isTop) {
if(isLeft) hitTest = HT.TOPLEFT;
else if(isRight) hitTest = HT.TOPRIGHT;
else hitTest = HT.TOP;
}
else if(isBottom) {
if(isLeft) hitTest = HT.BOTTOMLEFT;
else if(isRight) hitTest = HT.BOTTOMRIGHT;
else hitTest = HT.BOTTOM;
}
else if(isLeft) hitTest = HT.LEFT;
else if(isRight) hitTest = HT.RIGHT;
else if(mousePosition.Y <= captionHeight) hitTest = HT.CAPTION;
return new IntPtr((int)hitTest);
}
return IntPtr.Zero;
}
}
public class WindowHost : HwndHost {
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr CreateWindowEx(IntPtr exStyle, string lpClassName,string lpWindowName,int dwStyle,int x,int y,int nWidth,int nHeight,IntPtr hWndParent,IntPtr hMenu,IntPtr hInstance,IntPtr lpParam);
protected override HandleRef BuildWindowCore(HandleRef hWndParent) {
return new HandleRef(this, CreateWindowEx(IntPtr.Zero, "static", "", 0x40000000, 0, 0, 200, 200, hWndParent.Handle, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero));
}
protected override void DestroyWindowCore(HandleRef hwnd) { }
}
}
Bạn đã bao giờ tìm thấy bất kỳ giải pháp thay thế? – Seth
@Seth Không, nhưng thành thật mà nói tôi đã ngừng tìm kiếm sau khi tôi tìm thấy điều này .. cho tôi biết nếu bạn tìm ra một cái gì đó! – Roald