2012-09-08 168 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())达到最终结果(窗口大小调整)。这个解决方案也不会同时调整大小,所以动画并不尽如人意,但最终“起作用”。

相关问题