2010-08-02 18 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

相關問題