2010-08-02 21 views
7

我有一个没有标题栏的窗口(WindowStyle == WindowStyle.None)。整个窗口使用Aero玻璃效果。当我使窗口变得不可调整时(ResizeMode == ResizeMode.NoResize),玻璃效果消失,我的控件只能在半空中悬挂。 (本质上,窗口本身消失,但留下它的内容。)WPF:使窗口不可调整,但保持框架?

有没有办法让窗口变得不可调整而没有摆脱窗口框架?


我已阅读问题Enable Vista glass effect on a borderless WPF window,但是这并不完全我想要的东西 - 我想保持窗口边框。有关我希望窗口的外观的示例,请在启用了Aero的情况下按Alt + Tab。


为了澄清,我不希望调整大小光标悬停在窗口边框时出现在所有。实际上,这就是我希望我的窗口看起来像:

Projector http://i37.tinypic.com/2mg4jty.png

该解决方案不必严格WPF - 我很好,以便使用Win32 API周围的黑客来实现这一目标。

回答

9

您可以挂接wndproc并拦截WM_WINDOWPOSCHANGING消息。不是严格的WPF,但可能是你最好的选择。

如果你想隐藏调整大小的光标,那么你最好的选择是拦截WM_NCHITTEST。调用DefWindowProc(获取默认行为)并测试返回值;如果它是HTBOTTOM,HTBOTTOMLEFT,HTBOTTOMRIGHT,HTTOP,HTTOPLEFT或HTTOPRIGHT,请将返回值更改为HTBORDER。

+0

您仍然可以调整大小的光标,并且OP(在另一评论中)说这些不合需要。 – 2010-08-12 07:03:43

+0

工作就像一个魅力!谢谢!享受275更多代表。 :) – 2010-08-27 21:41:32

1

这样做的一个诡异的方法是设置MinWidth/MaxWidth和MinHeight/MaxHeight属性来有效地使其不可调整。当然,问题是你仍然可以通过边界获得调整大小的光标。

+0

好整点是摆脱调整大小光标,这样就不会帮忙,很遗憾。 – 2010-08-02 20:22:23

1

为什么不为窗口创建窗口边框? 它使用偏移来设置窗口的颜色。 所以,一个简单的方法就是将整个边框包裹在您的窗口周围,并且您可以获得自己的颜色!

+0

的时候我的意思是它环绕的窗口,我的意思是包装基本上 Kevin 2010-08-02 16:01:26

+0

但我不能让它匹配用户的当前主题。我可以创建一个与默认Aero主题完全相同的自定义边框,但如果用户已经对其进行了自定义(或使用了不同的主题),则该窗口将不匹配。 – 2010-08-02 20:23:32

+0

我并没有把这个答案扔掉,但是,我可能最终不得不这样做。 – 2010-08-02 20:53:25

9

基于Erics的回答。

Example Image

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> 
+0

自从他第一次发布这个想法以来,我会给埃里克的答案公平,但是感谢您的工作示例。 :) – 2010-08-27 21:42:18

+1

这就是为什么我提到它。我只是想看看我是否能得到它的工作。 – 2010-08-27 23:00:30

+1

不应该在所有情况下调用DefWindowProc?在此代码中,如果msg是WM_NCHITTEST,则只能调用原始函数。我会想象要正确地执行覆盖,其他任何消息都应该简单地返回原始函数给出的结果。 – Nyerguds 2011-04-26 14:20:30

相关问题