2013-06-18 53 views
6

我写了一个WindowExtension应该提供一个简单的翻译动画的窗口。但是这个动画在它到达目标坐标之前总是停止。有人可以给我一个建议,为什么?为什么我的WPF之前完成翻译动画停止?

问候 克里斯

public static class WindowExtensions 
    { 
     public static void Translate(this Window element, double x, double y, TimeSpan duration) 
     { 
     NameScope.SetNameScope(element, new NameScope()); 

     var xAnimation = new DoubleAnimationUsingKeyFrames {Duration = duration}; 
     xAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(element.Left, KeyTime.FromPercent(0))); 
     xAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(x, KeyTime.FromPercent(1))); 

     var yAnimation = new DoubleAnimationUsingKeyFrames {Duration = duration}; 
     yAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(element.Top, KeyTime.FromPercent(0))); 
     yAnimation.KeyFrames.Add(new EasingDoubleKeyFrame(y, KeyTime.FromPercent(1))); 

     var storyboard = new Storyboard() 
     { 
      Children = { xAnimation, yAnimation } 
     }; 

     Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(Window.Left)")); 
     Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(Window.Top)")); 

     storyboard.Duration = duration; 
     storyboard.FillBehavior = FillBehavior.Stop; 

     storyboard.Completed += (sender, args) => 
     { 
      storyboard.SkipToFill(); 
      storyboard.Remove(element); 
     }; 

     storyboard.Begin(element); 
     } 
    } 

它可以在WPF窗口简单地测试这样的:

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

     private void Button_Click(object sender, RoutedEventArgs e) 
     { 
     this.Translate(10,10, TimeSpan.FromMilliseconds(250)); 
     } 
    } 

回答

1

看起来像一个错字。最有可能是因为你的xAnimation动画Window.TopyAnimation动画Window.Left

Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(Window.Left)")); 
Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(Window.Top)")); 
+0

哦!这就是真实的,那是一个错字...我纠正我的错误,但我还是老样子得到相同的结果:( – ChrisTTian667

+1

Hmmmm,很奇怪,它是在我的情况不一致。我试着删除'Completed'事件,改变为'DoubleAnimation是'。甚至写了相同的动画在XAML中具有固定'To'值,有时到达目的地,有时没有。所有的大THX的 – dkozl

+0

首先测试的问题,我也打过电话中CompletedEventHandler递归翻译方法。 (当然仅用于测试目的)在那里,我发现了一些有趣的(奇怪)。我加了一个检查窗口的目标坐标的平等和实际的左侧和顶部的价值。他们是平等的,但窗口不位于此位置。 – ChrisTTian667

-1

我发现的东西,我需要工作,但它是非常肮脏,我想改变的东西很好的实施。所以,如果有人知道这是为什么?请告诉:)

public static void Translate(this Window element, double x, double y, TimeSpan duration) 
    { 
    var xAnimation = new DoubleAnimationUsingKeyFrames { Duration = duration }; 
    xAnimation.KeyFrames.Add(new LinearDoubleKeyFrame(element.Left, KeyTime.FromPercent(0.0))); 
    xAnimation.KeyFrames.Add(new LinearDoubleKeyFrame(x, KeyTime.FromPercent(1.0))); 

    var yAnimation = new DoubleAnimationUsingKeyFrames { Duration = duration }; 
    yAnimation.KeyFrames.Add(new LinearDoubleKeyFrame(element.Top, KeyTime.FromPercent(0.0))); 
    yAnimation.KeyFrames.Add(new LinearDoubleKeyFrame(y, KeyTime.FromPercent(1.0))); 

    Storyboard.SetTargetProperty(xAnimation, new PropertyPath("(Window.Left)")); 
    Storyboard.SetTargetProperty(yAnimation, new PropertyPath("(Window.Top)")); 

    var storyboard = new Storyboard 
    { 
     Children = { yAnimation, xAnimation }, 
     Duration = duration, 
     FillBehavior = FillBehavior.Stop, 
    }; 

    storyboard.Completed += (sender, args) => 
    { 
     storyboard.SkipToFill(); 
     storyboard.Remove(element); 

     element.InvalidateProperty(Window.LeftProperty); 
     element.InvalidateProperty(Window.TopProperty); 

     if (Math.Abs(element.Left - x) > Double.Epsilon || Math.Abs(element.Top - y) > Double.Epsilon) 
      Translate(element, x, y, TimeSpan.FromTicks(Math.Min(duration.Ticks/2, 100))); 
    }; 

    element.Dispatcher.Invoke(DispatcherPriority.ApplicationIdle, new Action(() => element.BeginStoryboard(storyboard))); 
    } 
4

WPF窗口定位/重新调整大小与它的DPI独立缩放一直是我的问题(尤其是当你想动画运动/尺寸平滑变化尊重监控DPI和多显示器设置)

我的确写了一个自定义的助手类,以帮助动画窗口尺寸这可能会帮助你。

主类(NativeWindowSizeManager):

using System; 
using System.Diagnostics.CodeAnalysis; 
using System.Runtime.InteropServices; 
using System.Windows; 
using System.Windows.Interop; 
using System.Windows.Media; 

/// <summary> 
/// C Enumerator to Represent Special Window Handles 
/// </summary> 
public enum SpecialWindowHandles { 
    kHwndTop = 0, 
    kHwndBottom = 1, 
    kHwndTopmost = -1, 
    kHwndNotopmost = -2 
} 

/// <summary> 
/// C Enumerator to Set Window Position Flags 
/// </summary> 
public enum SetNativeWindowPosition { 
    kNoSize = 0x0001, 
    kNoMove = 0x0002, 
    kNoZOrder = 0x0004, 
    kNoRedraw = 0x0008, 
    kNoActivate = 0x0010, 
    kDrawFrame = 0x0020, 
    kFrameChanged = 0x0020, 
    kShowWindow = 0x0040, 
    kHideWindow = 0x0080, 
    kNoCopyBits = 0x0100, 
    kNoOwnerZOrder = 0x0200, 
    kNoReposition = 0x0200, 
    kNoSendChanging = 0x0400, 
    kDeferErase = 0x2000, 
    kAsyncWindowPos = 0x4000 
} 

/// <summary> 
/// Class to perform Window Resize Animations 
/// </summary> 
public class NativeWindowSizeManager { 
    #region Member Variables 
    /// <summary> 
    /// Attached Dependency Property for Native Window Height 
    /// </summary> 
    public static readonly 
    DependencyProperty NativeWindowHeightProperty = DependencyProperty.RegisterAttached(
     "NativeWindowHeight", 
     typeof(double), 
     typeof(Window), 
     new PropertyMetadata(OnNativeDimensionChanged)); 

    /// <summary> 
    /// Attached Dependency Property for Native Window Width 
    /// </summary> 
    public static readonly 
    DependencyProperty NativeWindowWidthProperty = DependencyProperty.RegisterAttached(
     "NativeWindowWidth", 
     typeof(double), 
     typeof(Window), 
     new PropertyMetadata(OnNativeDimensionChanged)); 

    /// <summary> 
    /// Attached Dependency Property for Native Window Left 
    /// </summary> 
    public static readonly 
    DependencyProperty NativeWindowLeftProperty = DependencyProperty.RegisterAttached(
     "NativeWindowLeft", 
     typeof(double), 
     typeof(Window), 
     new PropertyMetadata(OnNativeDimensionChanged)); 

    /// <summary> 
    /// Attached Dependency Property for Native Window Top 
    /// </summary> 
    public static readonly 
    DependencyProperty NativeWindowTopProperty = DependencyProperty.RegisterAttached(
     "NativeWindowTop", 
     typeof(double), 
     typeof(Window), 
     new PropertyMetadata(OnNativeDimensionChanged)); 

    /// <summary> 
    /// Private member holding Dpi Factor 
    /// </summary> 
    private static double? _dpiFactor; 
    #endregion 

    #region Constructors 
    #endregion 

    #region Commands & Properties 
    #endregion 

    #region Methods 
    /// <summary> 
    /// Sets the native height. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <param name="value">The value.</param> 
    public static void SetNativeWindowHeight(UIElement element, double value) { 
    element.SetValue(NativeWindowHeightProperty, value); 
    } 

    /// <summary> 
    /// Gets the native height. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <returns>Native Height in pixels</returns> 
    public static double GetNativeWindowHeight(UIElement element) { 
    return (double)element.GetValue(NativeWindowHeightProperty); 
    } 

    /// <summary> 
    /// Sets the native width. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <param name="value">The value.</param> 
    public static void SetNativeWindowWidth(UIElement element, double value) { 
    element.SetValue(NativeWindowWidthProperty, value); 
    } 

    /// <summary> 
    /// Gets the native width. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <returns>Native Width in pixels</returns> 
    public static double GetNativeWindowWidth(UIElement element) { 
    return (double)element.GetValue(NativeWindowWidthProperty); 
    } 

    /// <summary> 
    /// Sets the native left. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <param name="value">The value.</param> 
    public static void SetNativeWindowLeft(UIElement element, double value) { 
    element.SetValue(NativeWindowLeftProperty, value); 
    } 

    /// <summary> 
    /// Gets the native left. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <returns>Native Left in pixels</returns> 
    public static double GetNativeWindowLeft(UIElement element) { 
    return (double)element.GetValue(NativeWindowLeftProperty); 
    } 

    /// <summary> 
    /// Sets the native top. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <param name="value">The value.</param> 
    public static void SetNativeWindowTop(UIElement element, double value) { 
    element.SetValue(NativeWindowTopProperty, value); 
    } 

    /// <summary> 
    /// Gets the native top. 
    /// </summary> 
    /// <param name="element">The element.</param> 
    /// <returns>Native Top in pixels</returns> 
    public static double GetNativeWindowTop(UIElement element) { 
    return (double)element.GetValue(NativeWindowTopProperty); 
    } 

    /// <summary> 
    /// Method to Get Dpi Factor 
    /// </summary> 
    /// <param name="window">Window Object</param> 
    /// <returns>Dpi Factor</returns> 
    public static double GetDpiFactor(Visual window) { 
    HwndSource windowHandleSource = PresentationSource.FromVisual(window) as HwndSource; 
    if (windowHandleSource != null && windowHandleSource.CompositionTarget != null) { 
     Matrix screenmatrix = windowHandleSource.CompositionTarget.TransformToDevice; 
     return screenmatrix.M11; 
    } 

    return 1; 
    } 

    /// <summary> 
    /// Method to Retrieve Dpi Factor for Window 
    /// </summary> 
    /// <param name="window">Requesting Window</param> 
    /// <param name="originalValue">Dpi Independent Unit</param> 
    /// <returns>Pixel Value</returns> 
    private static int ConvertToDpiDependentPixels(Visual window, double originalValue) { 
    if (_dpiFactor == null) { 
     _dpiFactor = GetDpiFactor(window); 
    } 

    return (int)(originalValue * _dpiFactor); 
    } 

    /// <summary> 
    /// Handler For all Attached Native Dimension property Changes 
    /// </summary> 
    /// <param name="obj">Dependency Object</param> 
    /// <param name="e">Property Arguments</param> 
    private static void OnNativeDimensionChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) { 
    var window = obj as Window; 
    if (window == null) 
     return; 

    IntPtr handle = new WindowInteropHelper(window).Handle; 
    var rect = new Rect(); 
    if (!GetWindowRect(handle, ref rect)) 
     return; 

    rect.X = ConvertToDpiDependentPixels(window, window.Left); 
    rect.Y = ConvertToDpiDependentPixels(window, window.Top); 
    rect.Width = ConvertToDpiDependentPixels(window, window.ActualWidth); 
    rect.Height = ConvertToDpiDependentPixels(window, window.ActualHeight); 

    if (e.Property == NativeWindowHeightProperty) { 
     rect.Height = ConvertToDpiDependentPixels(window, (double)e.NewValue); 
    } else if (e.Property == NativeWindowWidthProperty) { 
     rect.Width = ConvertToDpiDependentPixels(window, (double)e.NewValue); 
    } else if (e.Property == NativeWindowLeftProperty) { 
     rect.X = ConvertToDpiDependentPixels(window, (double)e.NewValue); 
    } else if (e.Property == NativeWindowTopProperty) { 
     rect.Y = ConvertToDpiDependentPixels(window, (double)e.NewValue); 
    } 

    SetWindowPos(
     handle, 
     new IntPtr((int)SpecialWindowHandles.kHwndTop), 
     rect.X, 
     rect.Y, 
     rect.Width, 
     rect.Height, 
     (uint)SetNativeWindowPosition.kShowWindow); 
    } 
    #endregion 

    #region Native Helpers 
    [DllImport("user32.dll", SetLastError = true)] 
    private static extern bool GetWindowRect(IntPtr windowHandle, ref Rect rect); 

    [DllImport("user32.dll")] 
    [return: MarshalAs(UnmanagedType.Bool)] 
    private static extern bool SetWindowPos(
    IntPtr windowHandle, IntPtr windowHandleInsertAfter, int x, int y, int cx, int cy, uint windowPositionFlag); 

    /// <summary> 
    /// C Structure To Represent Window Rectangle 
    /// </summary> 
    [SuppressMessage("Microsoft.StyleCop.CSharp.DocumentationRules", "SA1600:ElementsMustBeDocumented", 
    Justification = "This is an Implementation for C Struct")] 
    [StructLayout(LayoutKind.Sequential)] 
    public struct Rect { 
    public int X; 
    public int Y; 
    public int Width; 
    public int Height; 
    } 
    #endregion 
} 

现在为您的要求在Button.Click处理程序,你可以有这样的:

private void ButtonBase_OnClick(object sender, RoutedEventArgs e) { 
    var storyBoard = new Storyboard { Duration = new Duration(new TimeSpan(0, 0, 0, 0, 250)) }; 

    // Top 
    var aniTop = new DoubleAnimationUsingKeyFrames { Duration = new Duration(new TimeSpan(0, 0, 0, 0, 250)) }; 
    aniTop.KeyFrames.Add(new EasingDoubleKeyFrame(Top, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 00)))); 
    aniTop.KeyFrames.Add(new EasingDoubleKeyFrame(10, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 250)))); 
    Storyboard.SetTarget(aniTop, this); 
    Storyboard.SetTargetProperty(aniTop, new PropertyPath(NativeWindowSizeManager.NativeWindowTopProperty)); 
    storyBoard.Children.Add(aniTop); 

    // Left 
    var aniLeft = new DoubleAnimationUsingKeyFrames { Duration = new Duration(new TimeSpan(0, 0, 0, 0, 250)) }; 
    aniLeft.KeyFrames.Add(new EasingDoubleKeyFrame(Left, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 00)))); 
    aniLeft.KeyFrames.Add(new EasingDoubleKeyFrame(10, KeyTime.FromTimeSpan(new TimeSpan(0, 0, 0, 0, 250)))); 
    Storyboard.SetTarget(aniLeft, this); 
    Storyboard.SetTargetProperty(aniLeft, new PropertyPath(NativeWindowSizeManager.NativeWindowLeftProperty)); 
    storyBoard.Children.Add(aniLeft); 
    storyBoard.Begin(); 
} 

,它应该在工作的优良的每次全部上述情况。

NativeWindowSizeManager也有NativeWindowWidthNativeWindowHeight允许调整大小来进行动画或者像我的情况下,同时中心将当前窗口到屏幕动态显示窗口重新大小。

你可以得到这个项目的演示为您的使用情况:Here

相关问题