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.
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);
}
Can a storyboard be placed in a resource file such as styles.xaml? I have a toolbar that will be reused across many pages. I have this working now with a page level resource:
<navigation:Page.Resources>
<Storyboard x:Name="sbToolbarInitialization">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.TranslateY)"
Storyboard.TargetName="Toolbar">
<EasingDoubleKeyFrame KeyTime="0"
Value="46" />
<EasingDoubleKeyFrame KeyTime="0:0:1"
Value="0">
<EasingDoubleKeyFrame.EasingFunction>
<BackEase EasingMode="EaseOut" />
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</navigation:Page.Resources>
Which the border control uses:
<Border x:Name="Toolbar"
Style="{StaticResource ToolbarBorderStyle}">
<Border.RenderTransform>
<CompositeTransform />
</Border.RenderTransform>
<i:Interaction.Triggers>
<i:EventTrigger>
<ei:ControlStoryboardAction Storyboard="{StaticResource sbToolbarInitialization}" />
</i:EventTrigger>
</i:Interaction.Triggers>
</Border>
Since I am already using the style.xaml file to place formatting for the border I would like to also store the storyboard there. Is this possible?
I've done something similar, storing the Storyboard in my App.xaml file and using across my entire application. One way to access it in your code-behind or view-model is as such:
public Storyboard MyStoryBoard = Application.Current.Resources["MyStoryBoard "] as Storyboard;
You could then bind that storyboard property to your view declaratively.
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>
I have a WPF-View with an ItemsControl that binds an ObservableCollection from the ViewModel. Now i want to fade out slowly items which i remove from the ObservableCollection.
ViewModel:
public class ViewModel
{
public ObservableCollection<string> Items { get; set; }
}
View:
<Window x:Class="Sandbox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"
Name="mainWindow">
<Window.Resources>
<DataTemplate x:Key="mytemplate">
<DataTemplate.Resources>
<Storyboard x:Key="OnUnloaded">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="1"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="-0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0" Value="0"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="-10"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</DataTemplate.Resources>
<Grid x:Name="grid" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Grid.RenderTransform>
<TextBox Text="{Binding Mode=OneWay}"/>
</Grid>
<DataTemplate.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Unloaded">
<BeginStoryboard Storyboard="{StaticResource OnUnloaded}"/>
</EventTrigger>
</DataTemplate.Triggers>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ItemsControl Grid.Row="1" ItemsSource="{Binding Items}" ItemTemplate="{StaticResource mytemplate}"/>
</StackPanel>
The problem i have is now, that the storyboard begins by removing an item from the collection, but at the same time the itemscontrol remove the item and for this, the animation is not in sight...
any idea how to prevent remove the item before animation terminate?
This is much more difficult than it should be. The problem with a "remove" animation is that once an item is removed from the databound collection, its corresponding visuals are automatically removed from the element tree. This means that there is nothing left to animate out.
To work around it, you need to find a way to queue the animation before you remove the item from the databound collection and once the animation is complete, notify the ViewModel that it is okay to remove the item.
The other solution is to modify the behavior of the ItemsControl to better control the lifetime of the container visuals.
Either way, it is unfortunately not a trivial task to accomplish.
Animating the DropShadoweffect and OuterGlowBitmapEffect is keep on increasing the memory and CPU usage. Why it is taking too much memory and cpu usage and is there any way to reduce or avoid?
<Window.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00"
Storyboard.TargetName="textBlock"
Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.BlurRadius)"
RepeatBehavior="Forever">
<SplineDoubleKeyFrame KeyTime="00:00:00" Value="0"/>
<SplineDoubleKeyFrame KeyTime="00:00:00.9000000" Value="25"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Window.Resources>
<Window.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource Storyboard1}"/>
</EventTrigger>
</Window.Triggers>
<Grid x:Name="LayoutRoot">
<TextBlock x:Name="textBlock" HorizontalAlignment="Left" VerticalAlignment="Top" Text="Drop Shadow Effect" TextWrapping="Wrap" Margin="189,126,0,0" FontWeight="Bold">
<TextBlock.Effect>
<DropShadowEffect ShadowDepth="5" BlurRadius="0"/>
</TextBlock.Effect>
</TextBlock>
</Grid>
There is no such class as OuterGlowEffect.
Do you mean OuterGlowBitmapEffect? If so, this is a deprecated class with known performance issues, which could explain your problem. Use BlurEffect or another DropShadowEffect instead to achieve what you want. (Also, ensure you are not using the deprecated DropShadowBitmapEffect.)
But it could also be an issue with your code, in which case, post it up!