2012-09-08 167 views
5

我想爲wpf窗口的寬度和高度設置動畫效果。我已經嘗試了以下內容,不幸的是,它只是爲寬度設置動畫...窗口的高度永遠不會改變。爲WPF窗口寬度和高度設置動畫效果

我確定我錯過了一些愚蠢的東西,並希望通過張貼在這裏有人會看到我的錯誤!

下面的代碼背後有一個按鈕,我已經連接好做調整大小的一個簡單的窗口:

public partial class MainWindow : Window 
{ 
    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     this.AnimateWindowSize(ActualWidth + 200, ActualHeight + 200); 
    } 
} 

這裏是動畫代碼我已經寫了作爲一個擴展方法,以便它可以適用於任何窗口...

public static class WindowUtilties 
{ 
    public static void AnimateWindowSize(this Window target, double newWidth, double newHeight) 
    { 
     var sb = new Storyboard {Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200))}; 

     var aniWidth = new DoubleAnimationUsingKeyFrames(); 
     var aniHeight = new DoubleAnimationUsingKeyFrames(); 

     aniWidth.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)); 
     aniHeight.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 200)); 

     aniHeight.KeyFrames.Add(new EasingDoubleKeyFrame(target.ActualHeight, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 00)))); 
     aniHeight.KeyFrames.Add(new EasingDoubleKeyFrame(newHeight, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 200)))); 
     aniWidth.KeyFrames.Add(new EasingDoubleKeyFrame(target.ActualWidth, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 00)))); 
     aniWidth.KeyFrames.Add(new EasingDoubleKeyFrame(newWidth, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 200)))); 

     Storyboard.SetTarget(aniWidth, target); 
     Storyboard.SetTargetProperty(aniWidth, new PropertyPath(Window.WidthProperty)); 

     Storyboard.SetTarget(aniHeight, target); 
     Storyboard.SetTargetProperty(aniHeight, new PropertyPath(Window.HeightProperty)); 

     sb.Children.Add(aniWidth); 
     sb.Children.Add(aniHeight); 

     sb.Begin(); 
    } 
} 

在此先感謝您的任何幫助。

回答

2

在喬的使用pinvoke和依賴屬性的評論後,我結束了這段代碼。如果代碼很長,我現在會道歉,我不應該把它放在這裏。數學在大小上並不完美。 WPF實際(高度/寬度)與Rect.Height/Width之間有很大差異,可能需要一些計算才能獲得所需的確切大小。

將其加入到MainWindow類

[StructLayout(LayoutKind.Sequential)] 
public struct RECT 
{ 
    public int X; 
    public int Y; 
    public int Width; 
    public int Height; 
} 

public enum SpecialWindowHandles 
{ 
    HWND_TOP = 0, 
    HWND_BOTTOM = 1, 
    HWND_TOPMOST = -1, 
    HWND_NOTOPMOST = -2 
} 

[DllImport("user32.dll", SetLastError = true)] 
static extern bool GetWindowRect(IntPtr hWnd, ref RECT Rect); 

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); 

public static readonly DependencyProperty WindowHeightAnimationProperty = DependencyProperty.Register("WindowHeightAnimation", typeof(double), 
                          typeof(MainWindow), new PropertyMetadata(OnWindowHeightAnimationChanged)); 

private static void OnWindowHeightAnimationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var window = d as Window; 

    if (window != null) 
    { 
     IntPtr handle = new WindowInteropHelper(window).Handle; 
     var rect = new RECT(); 
     if (GetWindowRect(handle, ref rect)) 
     { 
      rect.X = (int)window.Left; 
      rect.Y = (int)window.Top; 

      rect.Width = (int)window.ActualWidth; 
      rect.Height = (int)(double)e.NewValue; // double casting from object to double to int 

      SetWindowPos(handle, new IntPtr((int)SpecialWindowHandles.HWND_TOP), rect.X, rect.Y, rect.Width, rect.Height, (uint)SWP.SHOWWINDOW); 
     } 
    } 
} 

public double WindowHeightAnimation 
{ 
    get { return (double)GetValue(WindowHeightAnimationProperty); } 
    set { SetValue(WindowHeightAnimationProperty, value); } 
} 

public static readonly DependencyProperty WindowWidthAnimationProperty = DependencyProperty.Register("WindowWidthAnimation", typeof(double), 
                          typeof(MainWindow), new PropertyMetadata(OnWindowWidthAnimationChanged)); 

private static void OnWindowWidthAnimationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
{ 
    var window = d as Window; 

    if (window != null) 
    { 
     IntPtr handle = new WindowInteropHelper(window).Handle; 
     var rect = new RECT(); 
     if (GetWindowRect(handle, ref rect)) 
     { 
      rect.X = (int)window.Left; 
      rect.Y = (int) window.Top; 
      var width = (int)(double)e.NewValue; 
      rect.Width = width; 
      rect.Height = (int) window.ActualHeight; 

      SetWindowPos(handle, new IntPtr((int)SpecialWindowHandles.HWND_TOP), rect.X, rect.Y, rect.Width, rect.Height, (uint)SWP.SHOWWINDOW); 
     } 
    } 
} 

public double WindowWidthAnimation 
{ 
    get { return (double)GetValue(WindowWidthAnimationProperty); } 
    set { SetValue(WindowWidthAnimationProperty, value); } 
} 

private void GrowClick(object sender, RoutedEventArgs e) 
{ 
    this.AnimateWindowSize(Width+200, Height+200); 
} 

/// <summary> 
/// SetWindowPos Flags 
/// </summary> 
public static class SWP 
{ 
    public static readonly int 
    NOSIZE = 0x0001, 
    NOMOVE = 0x0002, 
    NOZORDER = 0x0004, 
    NOREDRAW = 0x0008, 
    NOACTIVATE = 0x0010, 
    DRAWFRAME = 0x0020, 
    FRAMECHANGED = 0x0020, 
    SHOWWINDOW = 0x0040, 
    HIDEWINDOW = 0x0080, 
    NOCOPYBITS = 0x0100, 
    NOOWNERZORDER = 0x0200, 
    NOREPOSITION = 0x0200, 
    NOSENDCHANGING = 0x0400, 
    DEFERERASE = 0x2000, 
    ASYNCWINDOWPOS = 0x4000; 
} 

而在OP的代碼,因此我

Storyboard.SetTargetProperty(aniHeight, new PropertyPath(Window.HeightProperty)); 
Storyboard.SetTargetProperty(aniWidth, new PropertyPath(Window.WidthProperty)); 

改變高度和寬度的目標屬性

Storyboard.SetTargetProperty(aniHeight, new PropertyPath(MainWindow.WindowHeightAnimationProperty)); 
Storyboard.SetTargetProperty(aniWidth, new PropertyPath(MainWindow.WindowWidthAnimationProperty)); 

原來的答覆:

從我發現的代碼中沒有問題。當我改變將動畫添加到故事板(sb.Children.Add)實例的順序時,我得到了沒有寬度的高度動畫。

這使我相信,在第一個動畫正在發生時,其他動畫變爲無效。

我所能想到的就是讓它們一個接一個地動畫,一個動畫比另一個稍長。一旦第一個動畫完成,動畫就會變長。

var sb = new Storyboard { Duration = new Duration(new TimeSpan(0, 0, 0, 0, 300)) }; 

var aniWidth = new DoubleAnimationUsingKeyFrames(); 
var aniHeight = new DoubleAnimationUsingKeyFrames(); 

aniWidth.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 300)); 
aniHeight.Duration = new Duration(new TimeSpan(0, 0, 0, 0, 150)); 

aniHeight.KeyFrames.Add(new EasingDoubleKeyFrame(target.ActualHeight, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 00)))); 
aniHeight.KeyFrames.Add(new EasingDoubleKeyFrame(newHeight, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 150)))); 

aniWidth.KeyFrames.Add(new EasingDoubleKeyFrame(target.ActualWidth, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 150)))); 
aniWidth.KeyFrames.Add(new EasingDoubleKeyFrame(newWidth, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 300)))); 

即使不使用XAML故事板,我也可以同時調整窗口的高度和寬度。

+0

這就是我發現的......我想知道是否可能有使用並行時間線的解決方案,但我無法讓它工作。這個http://stackoverflow.com/questions/1769317/animate-window-resize-width-and-height-c-sharp-wpf?rq=1看起來像一個黑客,但也許這是使它工作的唯一途徑? –

+0

是的,它看起來可能需要手動完成。該鏈接是一個很好的發現。 –

+1

窗口上的這些頂級屬性中的一些有點奇怪,並且與其他WPF屬性的行爲不同,因爲它們位於Win32的邊界上。如果你想動畫他們在一起WPFy的方式來做到這一點將創建一個窗口上附加的DependencyProperty在封面p /調用支持HwndSource SetWindowPos。我沒有可用的Windows開發環境來編寫解決方案,因此將其作爲評論而不是答案。如果你在WPF 4.0之前這樣做,還有其他問題需要擔心。如果我很快有機會,我會寫一篇文章。 –

0

新DP的一個建議對我來說似乎有點矯枉過正,尤其是因爲解決方案承認它不會同時調整大小。在我的快速實驗中,通過添加延遲(通過Task.Run())達到最終結果(窗口大小調整)。這個解決方案也不會同時調整大小,所以動畫並不盡如人意,但最終「起作用」。

相關問題