I have a Storyboard with StringAnimationUsingKeyFrames:
<Storyboard>
<StringAnimationUsingKeyFrames Storyboard.TargetProperty="(Button.ToolTip)" Storyboard.TargetName="xButton">
<DiscreteStringKeyFrame KeyTime="0" Value="{Binding State,Converter={StaticResource StateToStringConverter},StringFormat={x:Static props:Resources.xToolTipText}}"/>
</StringAnimationUsingKeyFrames>
....
<Storyboard>
xToolTipText comes from Resources:
Press ({0} State)
The value received for resources is variable State (int) from Model.
The whole thing can not work because binding of DiscreteStringKeyFrame does not work (I think the reason is that he does not belong to the visual tree).
Which is another way I can do this?
I used proxy binding as this post:
How to bind to data when the DataContext is not inherited
And it worked.
Related
I am new to WPF and just starting to get used to it,
I want to move a page across the screen when I load it. The Code I using for that currently is :
<Storyboard>
<ThicknessAnimationUsingKeyFrames Storyboard.TargetProperty="Margin" BeginTime="00:00:00">
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="1920,0,0,0" />
<SplineThicknessKeyFrame KeyTime="00:00:02" Value="0,0,0,0" />
</ThicknessAnimationUsingKeyFrames>
<DoubleAnimation
Storyboard.TargetName="SummaryPageName"
Storyboard.TargetProperty="Opacity"
From="0" To="1" Duration="0:0:2"
AutoReverse="False">
</DoubleAnimation>
</Storyboard>
While this works fine for me, what I want is to not use hard values(1920) in value field of
<SplineThicknessKeyFrame KeyTime="00:00:00" Value="1920,0,0,0" />
Is there anyway to do that without specifying this value, so that it will work with other resolutions as well.
Thank you
Modify the KeyFrame value with code behind.
You should assign resource name to the storyboard resource to be found by code behind.
[XAML]
<Storyboard x:Key="myStoryboard">
Get the Storyboard object instance by referring x:Key.
[C#]
private void MainWindow_SizeChanged(object sender, SizeChangedEventArgs e)
{
Storyboard s = this.Resources["myStoryboard"] as Storyboard;
SplineThicknessKeyFrame k = (s.Children[0] as ThicknessAnimationUsingKeyFrames).KeyFrames[0] as SplineThicknessKeyFrame;
k.Value = new Thickness(e.NewSize.Width,0,0,0);
}
Also you may use data binding to change keyframe value. If you need to change a lot of keyframe resources, you should use data binding. Otherwise changing value manually is easy to prepare.
I have a Storyboard defined in a Resource-XAML (Opacity and Rendertransform). Now I'd like to use it on my different Usercontrols. Since this is a Fade-in animation, it's crucial that the logic of the Usercontrol starts after the animation ends.
So I know about the "Completed" event of a storyboard but I can't see, how to apply here, since I needed to define the Eventhandler on the UserControl consuming the animation. (There are several Usercontrols each with their own actions to perform after being loaded...)
The Styles have a Property called "BasedOn", here I can define the parent... Is there something similar at the Storyboard object too, or do I have to redesign my code?
Anyway if there is a better way for using Standard animations across the project than via Resourcedictionary, please advise me.
Thanks in advance,
Daniel
edit:
here there part of the resdic.
<Storyboard x:Key="ShowAndGrow">
<DoubleAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="RenderTransform.ScaleX"
To="1" />
<DoubleAnimation Duration="0:0:0.3"
Storyboard.TargetProperty="RenderTransform.ScaleY"
To="1" />
<DoubleAnimation Duration="0:0:0.1"
Storyboard.TargetProperty="Opacity"
To="1" />
</Storyboard>
I apply it in a Usercontrol
<UserControl.Triggers>
<EventTrigger RoutedEvent="FrameworkElement.Loaded">
<BeginStoryboard Storyboard="{StaticResource ShowAndGrow}">
</BeginStoryboard>
</EventTrigger>
</UserControl.Triggers>
an here I needed to add the completed Event somehow....
You can access a Storyboard from a Resources collection using the Resources property:
Storyboard storyboard = this.Resources["YourStoryboard"] as Storyboard;
However, you really need to get access to the DoubleAnimation elements, so you'll need to name them too. You'd then be able to reassign the target property like this:
Storyboard.SetTarget(YourDoubleAnimation, YourUiControl);
Storyboard.SetTargetProperty(YourDoubleAnimation,
new PropertyPath(Control.OpacityProperty));
You can find further examples in the Working with Animations Programmatically page on MSDN (ignore the fact that it is for Silverlight as it will work just the same in WPF).
So I followed Core-One's and Sheridan's suggestions and added the Storyboard in Codebehind using findresource. I just wonder, if the "correct" way were to define as much as possible in XAML, there is no way to adapt the templated animations...
Thanks guys to all of you!
BR,
Daniel
Private Sub UserControl_Loaded(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
Dim sb As Storyboard = FindResource("ShowAndGrow")
AddHandler sb.Completed, AddressOf StartAction
sb.Begin(Me)
End Sub
So, let's say I want to modify the DataContext of several visual elements in a dynamic fashion and that I want to do so as part of a Storyboard. I might do that like so:
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SomeVisualElement" Storyboard.TargetProperty="(FrameworkElement.DataContext)" Duration="0:0:0" >
<DiscreteObjectKeyFrame KeyTime="0:0:0" >
<DiscreteObjectKeyFrame.Value>
<Binding Path="Repository.GeneratedThings[0].Element" />
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
This has the effect of binding the Value of the DiscreteObjectKeyFrame to Repository.GeneratedThings[0].Element. When this Storyboard is applied, the DataContext of SomeVisualElement is set to Repository.GeneratedThings[0].Element. This is the equivalent, I think, of saying:
<UserControl x:Name="SomeVisualElement" DataContext="{Binding Path="Repository.GeneratedThings[0].Element"} />
This is functional, but what I'd like to do would be to have some way that the binding is maintained only in the visual element but not in the key frame. We have few visual elements but many Storyboards and KeyFrames, and we notice a performance hit proportional to the number of KeyFrames when, e.g., we update the GeneratedThings object (not the individual elements of the collection).
How can I set up the DiscreteObjectKeyFrame so that the DataContext ends up bound correctly but that the value of the DiscreteObjectKeyFrame isn't bound? Is this even a reasonable semantic distinction in the context of WPF/XAML between a value being a Binding and a value being bound?
Alternatively, is there another way to change the DataContext of several visual elements from within a Storyboard and that doesn't involve having each Storyboard maintaining a binding?
Imagine that you have the following code:
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SomeVisualElement" Storyboard.TargetProperty="SomeProperty" Duration="0:0:0" >
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value={Binding Foo} />
</ObjectAnimationUsingKeyFrames>
One should notice two problems here.
Every Storyboard will have to maintain this Binding.
When running this Storyboard actually the current value of Foo will be set to SomeProperty. Latter changes in Foo won't be affected.
I suggest the following. Create some dependency object with Foo as dependency property. For example:
<Grid.Resources>
<viewModel:FooContainer Foo={Binding Foo} x:Key="FooContainer" />
</Grid.Resources>
Use this container in Storyboard(s).
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="SomeVisualElement" Storyboard.TargetProperty="SomeProperty" Duration="0:0:0" >
<DiscreteObjectKeyFrame KeyTime="0:0:0" Value={StaticResource FooContainer} />
</ObjectAnimationUsingKeyFrames>
Modify ContentTemplate of a Control so you can bind to Foo property itself. Thus you can transfer binding and not value of Foo directly to a Control. Also Storyboard won't be affected by Foo value change.
We're writing a Prism based Silverlight application and we've got a whole bunch of pages in separate modules.
The transition between the pages is handled via navigation events and each module has the following methods implemented to show the page when navigated to and hide it when navigated from:
public void Show()
{
VisualStateManager.GoToState(this, "ShowState", true);
}
public void Hide()
{
VisualStateManager.GoToState(this, "HideState", true);
}
At the moment "ShowState" and "HideState" are defined in each module's XAML file so are duplicated far too many times.
<Grid x:Name="LayoutRoot">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup x:Name="VisualStates">
<VisualState x:Name="ShowState">
...
</VisualState>
<VisualState x:Name="HideState">
...
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
Where ... represents the Storyboard for each transition.
I've just spotted an error in the Storyboard definitions and at the moment I'm going to have to replicate the fix across all the files. It would be better if there was only one definition of the Storyboard which could be referenced in each file.
I've searched all morning for the right syntax but have had no luck what so ever.
How can I share this VisualStateManager between all our XAML files?
<Storyboard x:Key="ShowStoryboard">
<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="glow" Storyboard.TargetProperty="(UIElement.Opacity)">
<SplineDoubleKeyFrame KeyTime="00:00:00.3000000" Value="0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
<VisualState x:Name="ShowState">
<BeginStoryboard Storyboard="{StaticResource ShowStoryboard}"/>
</VisualState>
Referencing your Storyboard within XAML can be done as seen above. With the top most portion being a Storyboard stored as a Resource somewhere. After that you should be able to use the BeginStoryboard reference within your VisualState.
EDIT: The above appears possible within WPF however it is not possible in SL. As of current it does not appear the abilty to reuse a Storyboard or VisualState is possible in SL. You should still be able to achieve what you are trying to do by encapsulating the VisualStateManager behavior within a style applied to a custom control. This would provide you the single point of failure you are looking for.
Let's say that I have this storyboard:
<Storyboard x:Key="OnMouseEnterStoryboard">
<DoubleAnimation BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)" To="180" />
</Storyboard>
It's there a possibility that I can set the To property from code. Something like
DoubleAnimation BeginTime="00:00:00" Storyboard.TargetProperty="(UIElement.RenderTransform).(RotateTransform.Angle)" To="{Binding angle}" />
And when I want to apply this animation to have a possibility to set it?
I completely agree with what #Paul said : Storyboard property bindings are no different from "normal" way of binding properties.
Anyway, this, this, this, this, and this are the links that you should follow if you want some good examples on Storyboard and Animation with property binding.
Storyboards can have bindings, just like anything else - instead of trying to dig through and set this explicitly, bind it to something easier to get ahold of like the Window object or a ViewModel