2012-09-08 18 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

Joeがpinvokeと依存関係のプロパティを使用した後、私はこのコードを作成しました。コードが長くて、ここにすべて入れてはいけないなら、私は今、お詫び申し上げます。数学はサイズに完璧ではありません。実際のWPF(高さ/幅)とRect.Height/Widthの間にはかなりの違いがあります。必要な正確なサイズを取得するためには計算が必要になることがあります。

この

は私が

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

オリジナルの答えに応じて

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

高さと幅のターゲットのプロパティを変更メイン・ウィンドウクラス

[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のコードに追加されました:

あなたのコードに問題はないことが分かったからです。ストーリーボード(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

これも私が見つけたことです...私はparalleltimelinesを使って解決策があるのだろうかと思っていましたが、どちらもうまくいきませんでした。これはhttp://stackoverflow.com/questions/1769317/animate-window-resize-width-and-height-c-sharp-wpf?rq=1ハックのように思えるかもしれませんが、多分それを動作させる唯一の方法ですか? –

+0

はい、手動で行う必要があるようです。そのリンクは良い発見でした。 –

+1

Window上のこれらのトップレベルプロパティのいくつかはちょっと変わっていて、Win32の境界にあるので他のWPFプロパティと同じように動作しません。これらを一緒にアニメーション化したい場合は、WPFyの方法は、裏のHwndSourceのp/Invoke SetWindowPosの下にあるDependencyPropertyをWindowに作成することです。私はソリューションを書くために利用できるWindowsの開発環境を持っていないので、答えの代わりにコメントとしてこれを置く。 WPF 4.0以前でこれをやっているのであれば、心配する追加の問題があります。すぐにチャンスがあれば、私はslnを書くでしょう。 –

0

新しいDPでの1つの提案は、特にソリューションが同時にサイズを変更しないことを認識して以来、私には少し残酷に思えました。私の素早い実験では、1msの遅延(Task.Run()経由)を追加することで最終結果(ウィンドウのサイズ変更)が達成されました。このソリューションも同時にサイズ変更されないため、アニメーションはそれほどエレガントではありませんが、最終的には機能します。

関連する問題