2014-01-28 52 views
3

我想有一個自定義窗口自定義窗口樣式,以便隨後的幾個教程,由窗口樣式設置爲none,然後添加標題欄啓用該/恢復/最小化/關閉按鈕自己。最小化是通過簡單處理單擊事件和窗口狀態設置爲最小化來實現,但這並不表明你在Windows 7上看到的最小化的動畫,只是瞬間隱藏窗口,與其他窗口使用時感覺很奇怪做動畫,因​​爲你傾向於感覺應用程序正在關閉。與最小化的動畫

所以,反正是有使該動畫的? ..當您將WindowStyle更改爲無時,它似乎被禁用。

編輯:測試代碼

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     WindowStyle = WindowStyle.None; 
     InitializeComponent(); 
    } 

    [DllImport("user32.dll")] 
    static extern int SendMessage(IntPtr hWnd, uint msg, IntPtr wParam, IntPtr lParam); 

    protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) 
    { 
     base.OnMouseLeftButtonDown(e); 

     // this doesnt seem to animate 
     SendMessage(new WindowInteropHelper(this).Handle, 0x0112, (IntPtr)0xF020, IntPtr.Zero); 
    } 

    protected override void OnMouseRightButtonDown(MouseButtonEventArgs e) 
    { 
     base.OnMouseRightButtonDown(e); 

     WindowStyle = WindowStyle.SingleBorderWindow; 
     WindowState = WindowState.Minimized; 
    } 

    protected override void OnActivated(EventArgs e) 
    { 
     base.OnActivated(e); 

     Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None)); 
    } 
} 

回答

6

試驗了一下後編輯答案。

有兩種選擇: 您只需最小化和激活的窗口前更改樣式:

private void Button_OnClick(object sender, RoutedEventArgs e) 
{ 
    //change the WindowStyle to single border just before minimising it 
    this.WindowStyle = WindowStyle.SingleBorderWindow; 
    this.WindowState = WindowState.Minimized; 
} 

private void MainWindow_OnActivated(object sender, EventArgs e) 
{ 
    //change the WindowStyle back to None, but only after the Window has been activated 
    Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, new Action(() => WindowStyle = WindowStyle.None)); 
} 

這個解決方案有一個限制 - 如果你儘量減少它不動畫窗口它來自任務欄。

2.用SC_MINIMIZE參數發送它WM_SYSCOMMAND消息,並掛接到消息(HwndSource.FromHwnd(m_hWnd).AddHook(WindowProc))改變邊框樣式最小化窗口。

internal class ApiCodes 
{ 
    public const int SC_RESTORE = 0xF120; 
    public const int SC_MINIMIZE = 0xF020; 
    public const int WM_SYSCOMMAND = 0x0112; 
} 

private IntPtr hWnd; 

[DllImport("user32.dll")] 
public static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam); 


private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    hWnd = new WindowInteropHelper(this).Handle; 
    HwndSource.FromHwnd(hWnd).AddHook(WindowProc); 
} 

private void Button_Click(object sender, RoutedEventArgs e) 
{ 
    SendMessage(hWnd, ApiCodes.WM_SYSCOMMAND, new IntPtr(ApiCodes.SC_MINIMIZE), IntPtr.Zero); 
} 

private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 
{ 
    if (msg == ApiCodes.WM_SYSCOMMAND) 
    { 
     if (wParam.ToInt32() == ApiCodes.SC_MINIMIZE) 
     { 
      WindowStyle = WindowStyle.SingleBorderWindow; 
      WindowState = WindowState.Minimized; 
      handled = true; 
     } 
     else if (wParam.ToInt32() == ApiCodes.SC_RESTORE) 
     { 
      WindowState = WindowState.Normal; 
      WindowStyle = WindowStyle.None; 
      handled = true; 
     } 
    } 
    return IntPtr.Zero; 
} 

上述兩種方法都不是很好,因爲它們只是黑客。最大的缺點是,當你點擊按鈕時,你實際上可以看到邊框重新出現。我想看看其他人提出了什麼,因爲我不認爲這是一個好的答案。

+0

Thankyou。我能夠得到第二種工作方式,但不是第一種。第一個仍然不顯示任何動畫。我使用 – pastillman

+0

編輯了我的帖子,並使用代碼Im更新了我的答案。我有點不對。在這兩種情況下,當您單擊按鈕時,您都會注意到標題重新出現。但是當你自己發送消息時,窗口總是在最小化時動畫。如果您只是在點擊按鈕時更改邊框,則在通過任務欄將其最小化時不會生成動畫。 – Fayilt

+0

不好意思回來這麼晚了,我覺得這很好。它不是真的那麼明顯,直到你有非常複雜的內容與laggy渲染 – pastillman

1

如果您通過返回0來處理WM_NCCALCSIZE消息,請使用您自己的代碼(如果您想進行手動命中測試)或返回0並將WindowStyle設置爲SingleBorder,處理WM_NCHITTEST消息,該窗口將會運行像無邊框窗口,但它將啓用動畫。

如果完全有必要,您可能還需要處理WM_GETMINMAXINFO以修復最大化大小 - 因爲窗口的樣式是SingleBorder,所以它將剪裁邊框。

0

我發現了另一種解決方案,如果您需要AllowTransparency = True。 這不美麗,有點哈克。 但它非常簡單,效果很好。這將使用空的窗口,當你最小化/最大化/還原你的窗口,它即將更新顯示,並具有同樣的位置,widht,大小和高度爲你的窗口。它始終與窗口具有相同的窗口狀態,並且它執行動畫,由於WindowStyle無和AllowTransparency True,YourWindow缺少動畫。空窗口具有窗口樣式SingleBorderWindow和AllowTransparency = false。 (默認情況下,所以我不需要手動設置)這是一個必須或它不會動畫。動畫之後,它完全隱藏起來。如果看起來不錯,你可以調整虛假窗口的外觀(BackgroundColor等等)到YourWindow。最後

private void YourWindowClass_StateChanged(object sender, EventArgs e) 
    { 
     w.Left = Left; 
     w.Top = Top; 
     w.Width = Width; 
     w.Height = Height; 
     w.Show(); 

     if (WindowState == WindowState.Minimized) 
     { 
      if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal; 
      w.WindowState = WindowState.Minimized; 
      CloseWindow(); 
     } 
     if (WindowState == WindowState.Normal) 
     { 
      w.WindowState = WindowState.Normal; 
      w.Left = this.Left; 
      Activate(); 
      CloseWindow(); 

     } 
     if (WindowState == WindowState.Maximized) 
     {    
      w.WindowState = WindowState.Maximized; 
      Activate(); 
      CloseWindow(); 
     } 
    } 

,創建這個異步任務YourWindowClass:

public partial Class YourWindowClass : Window 
{ 

    Window w; 
    public YourWindowClass() 
    { 
     InitializeComponent(); 
     w = new Window(); 
     w.Width = Width; 
     w.Height = Height; 
     w.WindowStartupLocation = this.WindowStartupLocation;   
    } 

然後,你把這個在你的狀態更改事件。它會很快等待,然後隱藏額外的窗口。

public async Task CloseWindow() 
    { 
     await Task.Delay(600); 
     w.Visibility = Visibility.Hidden; 
    } 

這將刪除隱藏的黑客窗口,所以如果你關閉真正窗口中,哈克動畫窗口將關閉過。否則它不會被用戶看到,因爲它隱藏了,但它仍然是開放的,所以你的應用程序的某些部分是打開的。這是我們不想要的行爲,因此請將此作爲您的閉合事件:

private void YourWindowClass_Closed(object sender, EventArgs e) 
    { 
     w.Close(); 
    }