问题
I have a window that does not have a title bar (WindowStyle == WindowStyle.None
). The entire window uses the Aero glass effect. When I make the window unresizeable (ResizeMode == ResizeMode.NoResize
), the glass effect disappears and my controls just hang in midair. (Essentially, the window itself disappears but leaves its contents.)
Is there a way for me to make the window unresizeable without getting rid of the window frame?
I have read the question Enable Vista glass effect on a borderless WPF window, but that's not quite what I want--I would like to keep the window border. For an example of what I would like my window to look like, hit Alt+Tab with Aero enabled.
To clarify, I do no want the resize cursors to show up at all when hovering over the window border. This is essentially what I want my window to look like:
The solution doesn't have to be strictly WPF--I am fine with hacking around with the Win32 API in order to achieve this.
回答1:
You can hook the wndproc and intercept the WM_WINDOWPOSCHANGING message. Not strictly WPF, but probably your best bet.
If you want to hide the resize cursors, then your best bet is to intercept WM_NCHITTEST. Call the DefWindowProc (to get the default behavior), and test the return value; if it's HTBOTTOM, HTBOTTOMLEFT, HTBOTTOMRIGHT, HTTOP, HTTOPLEFT, or HTTOPRIGHT, change the return value to HTBORDER.
回答2:
Based on Erics answer.
public partial class MainWindow : Window
{
[DllImport("DwmApi.dll")]
public static extern int DwmExtendFrameIntoClientArea(
IntPtr hwnd,
ref MARGINS pMarInset);
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr DefWindowProc(
IntPtr hWnd,
int msg,
IntPtr wParam,
IntPtr lParam);
private const int WM_NCHITTEST = 0x0084;
private const int HTBORDER = 18;
private const int HTBOTTOM = 15;
private const int HTBOTTOMLEFT = 16;
private const int HTBOTTOMRIGHT = 17;
private const int HTLEFT = 10;
private const int HTRIGHT = 11;
private const int HTTOP = 12;
private const int HTTOPLEFT = 13;
private const int HTTOPRIGHT = 14;
public MainWindow()
{
InitializeComponent();
this.Loaded += new RoutedEventHandler(MainWindow_Loaded);
}
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
try
{
// Obtain the window handle for WPF application
IntPtr mainWindowPtr = new WindowInteropHelper(this).Handle;
HwndSource mainWindowSrc = HwndSource.FromHwnd(mainWindowPtr);
mainWindowSrc.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);
mainWindowSrc.AddHook(WndProc);
// Set Margins
MARGINS margins = new MARGINS();
margins.cxLeftWidth = 10;
margins.cxRightWidth = 10;
margins.cyBottomHeight = 10;
margins.cyTopHeight = 10;
int hr = DwmExtendFrameIntoClientArea(mainWindowSrc.Handle, ref margins);
//
if (hr < 0)
{
//DwmExtendFrameIntoClientArea Failed
}
}
// If not Vista, paint background white.
catch (DllNotFoundException)
{
Application.Current.MainWindow.Background = Brushes.White;
}
}
private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Override the window hit test
// and if the cursor is over a resize border,
// return a standard border result instead.
if (msg == WM_NCHITTEST)
{
handled = true;
var htLocation = DefWindowProc(hwnd, msg, wParam, lParam).ToInt32();
switch (htLocation)
{
case HTBOTTOM:
case HTBOTTOMLEFT:
case HTBOTTOMRIGHT:
case HTLEFT:
case HTRIGHT:
case HTTOP:
case HTTOPLEFT:
case HTTOPRIGHT:
htLocation = HTBORDER;
break;
}
return new IntPtr(htLocation);
}
return IntPtr.Zero;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
this.Close();
}
}
[StructLayout(LayoutKind.Sequential)]
public struct MARGINS
{
public int cxLeftWidth; // width of left border that retains its size
public int cxRightWidth; // width of right border that retains its size
public int cyTopHeight; // height of top border that retains its size
public int cyBottomHeight; // height of bottom border that retains its size
};
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="150" Width="200"
Background="Transparent"
WindowStyle="None"
ResizeMode="CanResize"
>
<Grid Background="White" Margin="10,10,10,10">
<Button Content="Go Away" Click="Button_Click" Height="20" Width="100" />
</Grid>
</Window>
回答3:
One hackish way to do it would be to set the MinWidth/MaxWidth and MinHeight/MaxHeight properties to effectively make it unresizeable. Of course, the problem there is you'll still get the resize cursors over the borders.
回答4:
Why don't you just create this window border for the window? It's using an offset to set the colors of the window. So, an easy way is just to wrap a whole border around your window and on top of that you get your own colors!
来源:https://stackoverflow.com/questions/3386486/wpf-make-window-unresizeable-but-keep-the-frame