Question

I'm trying to achieve the same animation than VS2012 setup window, autosizing and centering on every content size change in a nice animated way.

The problem is that it can't be done purely by code as I don't know the final window size (for what I rely on SizeToContent="WidthAndHeight"), but letting SizeToContent="WidthAndHeight" by it's own does not allow me to animate the transition

Is there any way to do it?

Was it helpful?

Solution

I think the simplest way to achieve this is to use custom visual states within your window class. I made a small test project that you can download here: https://dl.dropboxusercontent.com/u/14810011/ResizingWindow.zip

You need Visual Studio 2012 to execute it.

The Main Window XAML looks like this:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:ResizingWindow"
    xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions"
    x:Name="Window" x:Class="ResizingWindow.MainWindow"
    Title="MainWindow" Width="350" Height="300" WindowStyle="None" ResizeMode="NoResize" WindowStartupLocation="CenterScreen">
<Window.DataContext>
    <local:MainWindowViewModel />
</Window.DataContext>
  <Grid>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup x:Name="ExtendedStates">
            <VisualStateGroup.Transitions>
                <VisualTransition GeneratedDuration="0:0:0.6">
                    <VisualTransition.GeneratedEasingFunction>
                        <CubicEase EasingMode="EaseOut"/>
                    </VisualTransition.GeneratedEasingFunction>
                </VisualTransition>
            </VisualStateGroup.Transitions>
            <VisualState x:Name="Normal">
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="TextBlock">
                        <EasingDoubleKeyFrame KeyTime="0" Value="0"/>
                    </DoubleAnimationUsingKeyFrames>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="Window">
                        <EasingDoubleKeyFrame KeyTime="0" Value="300"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
            <VisualState x:Name="Extended">
                <Storyboard>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)" Storyboard.TargetName="Window">
                        <EasingDoubleKeyFrame KeyTime="0" Value="400"/>
                    </DoubleAnimationUsingKeyFrames>
                    <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="TextBlock">
                        <EasingDoubleKeyFrame KeyTime="0" Value="1"/>
                    </DoubleAnimationUsingKeyFrames>
                </Storyboard>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    <Grid.RowDefinitions>
        <RowDefinition Height="300"/>
        <RowDefinition Height="100"/>
    </Grid.RowDefinitions>
    <Border Background="#FF6C6C6C">
        <Grid>
            <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" Text="Hey, I here is some really cool content." VerticalAlignment="Top" FontSize="32" FontFamily="Segoe UI Light" TextAlignment="Center" Margin="0,50,0,0"/>
            <CheckBox Content="I want to see more" HorizontalAlignment="Center" VerticalAlignment="Bottom" Margin="0,0,0,15" IsChecked="{Binding ShowAdditionalContent}">
                <i:Interaction.Behaviors>
                    <ei:DataStateBehavior Binding="{Binding ShowAdditionalContent}" Value="False" TrueState="Normal" FalseState="Extended"/>
                </i:Interaction.Behaviors>
            </CheckBox>
            <Button Content="&#xE221;" HorizontalAlignment="Right" VerticalAlignment="Top" FontFamily="Segoe UI Symbol" FontSize="21.333" Style="{DynamicResource ButtonStyle}" Margin="0,5,5,0" Click="CloseMainWindow"/>
        </Grid>
    </Border>
    <Border Grid.Row="1" Background="#FF383838">
        <TextBlock x:Name="TextBlock" TextWrapping="Wrap" Text="You can see this, when the check box is activated." FontFamily="Segoe UI Light" FontSize="18.667" TextAlignment="Center" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="Silver"/>
    </Border>
  </Grid>
</Window>

The aspects you have to notice are the following:

  • The main window consists of a grid whose second row is hidden by default. This is achieved by setting the window height to 300 while the grid actually uses 400 logical units. One could also calculate this height dynamically during runtime, but for this simple example, this is not necessary.
  • The second row becomes visible when the "Extended" visual state is activated. This is actually done using the check box which updates the corresponding view model and the attached DataStateBehavior (this is part of the Blend SDK) that responds to it. When the state is changed, this behavior ensures that the corresponding visual state is activated, i.e. "Normal" when the checkbox is unchecked and "Extended" when it is checked.
  • The WindowStyle is set to None and the ResizeMode is set to NoResize. This ensures that no border is shown around the window. There is also the option to set AllowTransparency to true but I wouldn't recommend that as this has some serious performance implications. Notice that the default Minimize, Maximize/Restore and Quit buttons will not be present in this modus, too.

Please feel free to ask if you have further questions.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top