2013-06-18 14 views
6

Bir pencereye basit bir Çevirme animasyonu sağlaması gereken bir WindowExtension yazdım. Ancak bu Animasyon, hedef koordinatlara ulaşmadan önce her zaman durur. Herkes bana neden tavsiyede bulunabilir?WPF Translate Animation'ım neden tamamlanmadan önce duruyor?

Saygılarımızla chris

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); 
     } 
    } 

Bu sadece böyle bir WPF Pencerede test edilebilir:

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

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

cevap

1

bir yazım hatası benziyor.

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

Oh! Thats gerçek, şu benim hata düzeltilmiş ... bir yazım hatası oldu, ama hala :( – ChrisTTian667

+1

Hmmmm, çok garip aynı sonucu almak ve onu DoubleAnimation 'değişen, Completed' olay' kaldırarak. Ben denedim benim durumumda tutarsız '. Hatta sabit' To' değerlerle XAML aynı animasyonlar yazmış ve bazen hedef noktasına ulaşır ve bazen de vermez. bütün büyük thx ait – dkozl

+0

Birinci Sorunu test etmek için. Ben de CompletedEventHandler içinde yinelemeli yöntemi Çevir aramayı denedim. (Tabii ki sadece test amaçlı) Komik bir şey buldum (garip), hedef koordinatlarının eşitliği ve pencerenin gerçek sol ve üst değerleri için bir kontrol ekledim.Onlar aynıydı, ancak pencere bu pozisyonda değildi. konumu. – ChrisTTian667

-1

benim ihtiyaçları için çalışan bir şey buldum, ama çok kirli ve ben güzel bir şey ile uygulanmasını değiştirmek istiyorum: Büyük olasılıkla sizin xAnimationWindow.Top canlandıran ve yAnimationWindow.Left animasyon almasıdır. Herkes bilir neden Yani, eğer ... :)

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 Pencere konumlandırma söyle/yeniden boyutlandırma o DPI bağımsız ölçekleme hep bana (sen hareket/boyutunu animasyon istiyorum özellikle için bir sorun olmuştu var olan Monitör DPI ve çoklu monitör ayarlarına düzgün bir şekilde uyum sağlar.)

Size yardımcı olabilecek Pencere boyutlarını canlandırmaya yardımcı olmak için özel bir yardımcı sınıf yazdım.

ana sınıfı (NativeWindowSizeManager): İhtiyaçlarınız için Şimdi

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 
} 

sizin Button.Click işleyicisindeki gibi bir şey olabilir:

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(); 
} 

ve altında ince her zamanı çalışmalıdır tüm Yukarıda belirtilen durumlar.

NativeWindowSizeManager da animasyonlu veya geçerli pencere ekranına ortalarken bir pencere yeniden boyutunu canlandırmak benim durumumda gibi edilecek bir NativeWindowWidth ve NativeWindowHeight sağlayan yeniden boyutlandırma vardır.

Sen kullanım örneği için bu projenin bir demo alabilirsiniz: Here

İlgili konular