I'd like a way to display a list of text strings that fades like the following:
If you're using Office 2010, the effect is used in the new splash screens.
What I'd like is to have the last item selected and all items above faded so we achieve a similar affect. As items are added, the new item is selected and the previous item moves up and fades away.
Any ideas?
You can use a ListBox to achieve what you want.
In Silverlight 4, there is a new group of states LayoutStates available within ListBoxItem style.
It has three visual states, AfterLoaded, BeforeUnloaded and BeforeLoaded.
As the names imply, the BeforeLoaded state occurs right before the
ListBoxItem is added to the ListBox and the AfterLoaded state happens
after the ListBoxItem is added. BeforeUnloaded happens right before the ListBoxItem is removed.
In your case, you need to animate the fade in (Opacity and TranslateY) in the BeforeLoaded state when you try to add a new line of text, and animate the fade out in the BeforeUnloaded state when you try to remove the top line. Below is just one simple example.
<Style x:Key="AnimatedListBoxItemStyle" TargetType="ListBoxItem">
...
<VisualStateGroup x:Name="LayoutStates">
<VisualStateGroup.Transitions>
<VisualTransition GeneratedDuration="0:0:0.4" To="BeforeUnloaded">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="LayoutRoot">
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="-37" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="LayoutRoot">
<EasingDoubleKeyFrame KeyTime="0" Value="1" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition GeneratedDuration="0:0:1" />
</VisualStateGroup.Transitions>
<VisualState x:Name="BeforeUnloaded" />
<VisualState x:Name="BeforeLoaded">
<Storyboard>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)" Storyboard.TargetName="LayoutRoot">
<EasingDoubleKeyFrame KeyTime="0" Value="37" />
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="0" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Opacity)" Storyboard.TargetName="LayoutRoot">
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="1" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState x:Name="AfterLoaded" />
</VisualStateGroup>
Because after you removed the first line, the rest ListBoxItems will jump up at once to fill the empty space. To make this transition fluidly, you can overwrite the ListBox's ItemsPanel with a normal StackPanel, and attach a FluidMoveBehavior to it. Remeber to set the AppliesTo to Children. This means the animation will happen to the ListBox's children which are the ListBoxItems.
<ItemsPanelTemplate x:Key="ItemsPanelTemplate">
<StackPanel>
<i:Interaction.Behaviors>
<ei:FluidMoveBehavior AppliesTo="Children"/>
</i:Interaction.Behaviors>
</StackPanel>
</ItemsPanelTemplate>
Hope this helps. :)
UPDATE
You use OpacityMask to create the fade.
<ScrollViewer Padding="0" HorizontalAlignment="Center" Width="180" Height="300" VerticalAlignment="Center" VerticalScrollBarVisibility="Disabled" BorderThickness="0">
<ScrollViewer.OpacityMask>
<LinearGradientBrush StartPoint="0,0" EndPoint="0,1">
<GradientStop Color="Transparent" Offset="0" />
<GradientStop Color="Black" Offset="0.1" />
</LinearGradientBrush>
</ScrollViewer.OpacityMask>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Text="First Line" FontSize="14.667"/>
<TextBlock Text="Second Line" Grid.Row="1" FontSize="14.667"/>
</Grid>
</ScrollViewer>
Related
I'm pulling my hair out trying to get this to work. Im trying to learn to do transitions and struggling a bit. Basically im making a combo box, made up of a grid containing 2 rows. top row is a button, when clicked the bottom row opens up showing a scrollviewer of dynamically added buttons. When clicked, the bottom grid row will collapse.
The problem is that the Click event does not seem to fire from within the scroll viewer, or it can't find the visual state in the scope or something.
So it the SelectionMode works fine when Button11 is clicked, but nothing happens when I click on an item button. The buttons is the scrollviewer work perfectly with their own color animations and firing events etc
Id be open to a solution in code-behind since I can make routed click event fire no problem, but I had had no luck with
VisualStateManager.GoToState(gridContent, "HiddenMode", true);
Ideally I'd like this to be a custom user control I can add like local:CustomComboBox but It complicated for me at this stage having controls inside controls in a custom control.
MyButton1 is just a simple button but with color transitions etc
No exceptions / errors just nothing happens when I click the button
<Window.Resources>
<Storyboard x:Key="sb1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="gridContent" Storyboard.TargetProperty="Height">
<EasingDoubleKeyFrame KeyTime="0" Value="30" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="160" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="scrItems" Storyboard.TargetProperty="Height">
<EasingDoubleKeyFrame KeyTime="0" Value="0" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="130" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<Storyboard x:Key="sb2">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="gridContent" Storyboard.TargetProperty="Height">
<EasingDoubleKeyFrame KeyTime="0" Value="160" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="30" />
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="scrItems" Storyboard.TargetProperty="Height">
<EasingDoubleKeyFrame KeyTime="0" Value="130" />
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Grid Name="Grid1" Margin="0,22,0,0" RenderTransformOrigin="0.5,0.5">
<Grid Name="gridContent" HorizontalAlignment="Left" Margin="187,74,0,0" VerticalAlignment="Top" Width="140" Height="30" RenderTransformOrigin="0.5,0.5">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStateGroup">
<VisualState x:Name="SelectionMode" Storyboard="{StaticResource sb1}" />
<VisualState x:Name="HiddenMode" Storyboard="{StaticResource sb2}" />
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<local1:Button1 Name="Button11" Content="Click" Height="30" Grid.Row="0" Margin="0,0,0,30">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction TargetName="gridContent" StateName="SelectionMode" />
</i:EventTrigger>
</i:Interaction.Triggers>
</local1:Button1>
<ScrollViewer Name="scrItems" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden" Margin="0" Width="140" Height="0" Grid.Row="1">
<ItemsControl x:Name="stkItems">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<local1:Button1 Content="Click" Height="30">
<i:Interaction.Triggers>
<i:EventTrigger EventName="Click">
<ei:GoToStateAction TargetName="gridContent" StateName="HiddenMode" />
</i:EventTrigger>
</i:Interaction.Triggers>
</local1:Button1>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
</Grid>
</Grid>
private void Window_Loaded(object sender, RoutedEventArgs e)
{
lstItems = new ObservableCollection<MyButton.Button1>();
for (int i = 0; i <= 999; i++)
{
MyButton.Button1 item1 = new Button1();
item1.Content = "Item " + i;
item1.Width = stkItems.Width;
item1.Height = 30;
//item1.Click += new RoutedEventHandler(Button_Item_Click);
lstItems.Add(item1);
}
stkItems.DataContext = this.stkItems;
stkItems.ItemsSource = lstItems;
}
SOLVED!!!
I moved the visualStateManager to the root element - Grid1, but dont know if that affects it
private void Button_Item_Click(object sender, RoutedEventArgs e)
{
bool g = ExtendedVisualStateManager.GoToElementState(this.Grid1 as FrameworkElement, "HiddenMode", true);
}
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?
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="" 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.
I've video player with two button: Play and Pause.
I want to use only one button. when user clicks on Play, the button appearance will changed to Pause and vice versa.
What is the better approach to achieve that task without using cs code behind?
I've tried to use DataTrigger to my IsPlaying property, but with no much success....
Here is my code:
<Window.Resources>
<Viewbox x:Key="viewboxSource" >
<Viewbox.Triggers>
<DataTrigger Binding="{Binding IsPlaying}" Value="True">
<Setter Property="Path">
<Setter.Value>
<Path Stroke="Black" StrokeThickness="1" Fill="AliceBlue">
<Path.Data>
<GeometryGroup>
<EllipseGeometry Center="100,100" RadiusX="100" RadiusY="100"/>
</GeometryGroup>
</Path.Data>
</Path>
</Setter.Value>
</Setter>
</DataTrigger>
</Viewbox.Triggers>
</Viewbox>
</Window.Resources>
<StackPanel>
<Button Content="{StaticResource viewboxSource}"></Button>
</StackPanel>
But I gut an error that says " 'Path' member is not valid because it does not have a qualifying type name " .
Can anyone can help or give me a better solution?
These kind of behaviour fits toggle button patern.
Make a style in your resources
<Style x:Key="PlayToggleButtonStyle" TargetType="ToggleButton" >
and then define a templeate in it
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ToggleButton">
What is the most important here is to use VisualStateManager.
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Disabled"/>
<VisualState x:Name="Normal"/>
<VisualState x:Name="MouseOver"/>
<VisualState x:Name="Checked">
<Storyboard>
<DoubleAnimation Duration="0" To="2" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateX)" Storyboard.TargetName="border" />
<ColorAnimation Duration="0:0:0.2" To="#FF392929" Storyboard.TargetProperty="(Border.Background).(GradientBrush.GradientStops)[0].(GradientStop.Color)" Storyboard.TargetName="border"/>
</Storyboard>
</VisualState>
<VisualState x:Name="Pressed">
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
I use 2 animation. One moves button for 2 pixels and second change the gradient which gives a nice experience.
The only drawback is you need to use storyboards to handle these states. You need to add a Path object which I called Geometry nad mainupulate it.
<Storyboard Storyboard.TargetName="Geometry"
Storyboard.TargetProperty="Data">
<ObjectAnimationUsingKeyFrames>
<DiscreteObjectKeyFrame KeyTime="0" Value=""/> <!-- place the data here (how your button looks like) -->
</ObjectAnimationUsingKeyFrames>
</Storyboard>
But IMHO the better solution is to place 2 Path object in the template that on is over another and change the opacity of the top-most one.
<Storyboard>
<DoubleAnimation Storyboard.TargetName="TopGeometry" Storyboard.TargetProperty="Opacity" Duration="0:0:0.5" To="0.0">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
You would have a nice transition between these two states. What is more, no data is needed f.e IsPLaying property.
I wrote simple template in xaml for button s.(for silver-light 4)
So when I try use "ControlTemplate.Triggers", I found that is impossible in silver-light, and we must use Visual-State in Silver-Light
so I wrote first ControlTemplate with Visual-State but it not work fine.(here is code)
<Style x:Key="NextButtonStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid x:Name="MainGrid">
<Border x:Name="MainBorder"
BorderThickness="2"
BorderBrush="#FFC0C0C0"
Background="Bisque"
CornerRadius="4 4 4 4" >
<TextBlock x:Name="lbl"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Text=">"
Foreground="#FFC0C0C0"
FontWeight="Bold"
FontFamily="TimesNewRoman"
FontSize="15"/>
</Border>
<vsm:VisualStateManager.VisualStateGroups>
<vsm:VisualStateGroup x:Name="CommonStates">
<vsm:VisualState x:Name="MouseOver">
<Storyboard>
<ColorAnimationUsingKeyFrames AutoReverse="False" Duration="00:00:00.2"
Storyboard.TargetName="MainBorder"
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color}">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF606060"/>
</ColorAnimationUsingKeyFrames>
<ColorAnimationUsingKeyFrames AutoReverse="False" Duration="00:00:00.2"
Storyboard.TargetName="lbl"
Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color}">
<SplineColorKeyFrame KeyTime="00:00:00" Value="#FF606060"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</vsm:VisualState>
</vsm:VisualStateGroup>
</vsm:VisualStateManager.VisualStateGroups>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When i use this style and move on this border this border, both of border and textbloc became invisible. so
1) What do i do?
2) and is there any good examples for Visual-State
Because of two simple mistakes u r style was not working , else all is right.
1)Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color}
It will be :
Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)
2) The same goes for the textblock :
Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color}
It will be :
Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)
I've made a simple storyboard that takes a particular ListBoxItem and lets it grow by a factor of 1.3. I'd like to add this animation to every ListBoxItem I create dynamically so that it can be activated when it gets a mouse-over, but the storyboard seems to be hardcoded to that first item:
<Storyboard x:Name="ListItem_MouseEntered">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="RecentNews" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1.3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="RecentNews" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1.3"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
How should I go about duplicating this storyboard and setting the target to every listboxitem?
Cheers
Nik
PS, I believe I have some errors in the animation, don't worry about that, it's not part of my question :-)
You can define a ControlTemplate for ListBoxItem in the Resources section of the UserControl like this:
<ControlTemplate x:Key="LIT" TargetType="ListBoxItem">
<Border x:Name="MainBorder" BorderBrush="Red" BorderThickness="2" Background="Yellow" MouseEnter="Border_MouseEnter">
<Border.Resources>
<Storyboard x:Name="ItemStory">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ItemTransform" Storyboard.TargetProperty="ScaleX">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1.3"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="ItemTransform" Storyboard.TargetProperty="ScaleY">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="1.3"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Border.Resources>
<Border.RenderTransform>
<ScaleTransform x:Name="ItemTransform" />
</Border.RenderTransform>
<TextBlock Text="{TemplateBinding Content}" />
</Border>
</ControlTemplate>
Handle the MouseEnter event:
private void Border_MouseEnter(object sender, MouseEventArgs e)
{
Border itemBorder = (Border)sender;
Storyboard itemStory = (Storyboard)itemBorder.FindName("ItemStory");
itemStory.Begin();
}
And use it like this in XAML:
<ListBox x:Name="MyList">
<ListBox.Items>
<ListBoxItem Content="Toto 1" Template="{StaticResource LIT}" />
</ListBox.Items>
</ListBox>
Or like this in C#:
MyList.Items.Add(new ListBoxItem()
{
Content="Toto 2",
Template = (ControlTemplate)Resources["LIT"]
});
If you use the visual state manager, you can apply this to all of type:
This shows how to do just that.