Here is an interesting topic I found about window animation in WPF. Credits go to Chango V. from Microsoft who posted this solution here: http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/fd178a78-433f-4879-9b85-a90bbb3c7282
Quote:
Window resizing is a complex problem. Its smoothness depends on having good integration between multiple layers in the system. WPF uses DirectX for rendering, and it responds to WM_PAINT asynchronously. This is one of the fundamental causes for resizing “choppiness”. There will be some incremental improvements made for window resizing at the OS level in future releases/SPs that help WPF in particular.
Another potential source of unsmoothness is the Window class API. If you try to animate more than one of Top,Left,Width,Height at the same time, we’ll be making multiple calls to the native MoveWindow() function, with coordinates that are not smoothly changing. We are looking into this problem now and will probably publish a workaround sample. You can implement this workaround easily yourself:
Declare a DependencyProperty on a class derived from Window, called WindowRect. In the property changed callback, call the Win32 MoveWindow() function with Left,Top,ActualWidth,ActualHeight as parameters.
Set up your animation like this:
<Storyboard x:Key="sb" Storyboard.TargetName="win">
<RectAnimation Storyboard.TargetProperty="WindowRect" By="0, -200, 200, 0" Duration="0:0:4" />
</Storyboard>
Well, I wanted to have the window resized in its width, to expand for details display and contract back after removing a selection.. this was not possible with this approach because the By Property of the Storyboard doesn’t allow a negative value for the Width and Height Parameters (It’s a Rect!). But it pushed me into the right direction. So here is what I did. A lot code behind, but it works:
XAML of the MainWindow:
<Window x:Class="Timos_Window_Resizer.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Timos Resizing Window" Height="350" Width="300"
WindowStartupLocation="CenterScreen" ResizeMode="NoResize"
x:Name="TimosResizingWindow">
<Grid>
<StackPanel>
<Button Click="Expand_Click" Height="50" Margin="10">Expand to the left</Button>
<Button Click="Contract_Click" Height="50" Margin="10" >Contract from left</Button>
</StackPanel>
</Grid>
</Window>
C# code behind of the Window:
using System;
using System.ComponentModel;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media.Animation;
namespace Timos_Window_Resizer
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
// In constructor subscribe to the Change even of the WindowRect DependencyProperty
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(WindowRectProperty, typeof(MainWindow));
if (dpd != null)
{
dpd.AddValueChanged(this, delegate
{
ResizeWindow(WindowRect);
});
}
}
#region Button Events
public void Expand_Click(object sender, RoutedEventArgs e)
{
// Initialize WindowRect to the current size and position
WindowRect = new Rect(Left, Top, ActualWidth, ActualHeight);
// Define desired size
Rect expandedRect = new Rect(Left, Top, ActualWidth + 200, ActualHeight);
// Animated Resizing starts here
StartStoryBoard(WindowRect, expandedRect);
}
public void Contract_Click(object sender, RoutedEventArgs e)
{
// Initialize WindowRect to the current size and position
WindowRect = new Rect(Left, Top, ActualWidth, ActualHeight);
// Define desired size - do not get below 0
Rect contractedRect = new Rect(Left, Top, Math.Max(100, ActualWidth - 200), ActualHeight);
// Animated Resizing starts here
StartStoryBoard(WindowRect, contractedRect);
}
#endregion
#region Window Resizing
#region Dependency Property WindowRect
public Rect WindowRect
{
get
{
return (Rect)GetValue(WindowRectProperty);
}
set
{
SetValue(WindowRectProperty, value);
}
}
// Using a DependencyProperty as the backing store for WindowRect. This enables animation, styling, binding, etc...
public static readonly DependencyProperty WindowRectProperty =
DependencyProperty.Register("WindowRect", typeof(Rect), typeof(MainWindow), new UIPropertyMetadata(new Rect(0, 0, 0, 0)));
#endregion
#region Win32 Import of ModeWindow for better resizing without flickering
[DllImport("user32.dll", SetLastError = true)]
internal static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
#endregion
/// <summary>
/// Resizes the window to the desired Rect
/// Called when WindowRect DependencyProperty changes
/// </summary>
/// <param name="value">The target Rect containing size and Position</param>
private void ResizeWindow(Rect value)
{
IntPtr windowPtr = new WindowInteropHelper(this).Handle;
MoveWindow(windowPtr, (int)value.Left, (int)value.Top, (int)value.Width, (int)value.Height, true);
}
#endregion
#region Resize Animation
private void StartStoryBoard(Rect currentRect, Rect targetRect)
{
// Set up animation duration and behavior
RectAnimation rectAnimation = new RectAnimation();
rectAnimation.Duration = TimeSpan.FromSeconds(0.5);
rectAnimation.FillBehavior = FillBehavior.HoldEnd;
// Set the From and To properties of the animation.
rectAnimation.From = currentRect;
rectAnimation.To = targetRect;
// Set the Target of the animation to the Window
// Remember to define a name in XAML
Storyboard.SetTargetName(rectAnimation, "TimosResizingWindow");
Storyboard.SetTargetProperty(rectAnimation, new PropertyPath(WindowRectProperty));
// Create a storyboard to apply the animation.
Storyboard storyBoard = new Storyboard();
storyBoard.Children.Add(rectAnimation);
storyBoard.Begin(this);
}
#endregion
}
}
Here is the sample project. Download: Timos_Window_Resizer.zip
Letzte Kommentare