我想为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();
}
}
提前感谢您的帮助。
答案 0 :(得分:2)
在Joe对使用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));
原始答案:
根据我的发现,您的代码没有问题。当我改变动画添加到storyboard(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故事板,我也可以同时调整窗口的高度和宽度。
答案 1 :(得分:0)
对于我来说,使用较新的DP的一个建议似乎有点矫枉过正,特别是因为解决方案承认它仍然不会同时调整大小。在我的快速实验中,添加偶数1ms的延迟(通过Task.Run())实现了最终结果(窗口调整大小)。这个解决方案也没有同时调整大小,因此动画并不像它那样优雅,但它最终“有效”。