これについて数日間考えていましたが、Windowsとwpfが内部的にどのように動作するかを理解できていないと思います。ウィンドウにHwndHost要素が含まれている場合、サイズ変更時にカスタムdwm描画ウィンドウ枠がちらつく
問題はこれです:
私は私が(オフィスなど)エアロタイトルバーにWPFコントロールを描画させてくださいウィンドウを作成しました。 これは、ウィンドウにHwndhost要素を追加しない限り、この場合はうまく動作します。この場合、フレームサイズを変更し、HwndHostがちらつきを開始する(他の要素は適切にレンダリングされるようです)。私もWPF Shell Integration libraryからのカスタムフレームウィンドウの実装を使ってみました。結果は同じです。だから、それは私のせいではないと思っています。
次のコードは、問題を再現する単純なコンパイル可能なプログラムです。 サンプルはC#にありますが、答えはそうである必要はありません。
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) { }
}
}
あなたは今までどんな代替ソリューションを見つけましたとき、私はスタイルとしてWS_CLIPCHILDRENを追加することによってそれを解決? – Seth
@Sethいいえ、正直言って私はこの1つを見つけたのを見て止めました。あなたが何かを見つけたら教えてください! – Roald