WPF Storyboard - 相同的触发器,但行为相反
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/19376757/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Storyboard - same trigger, but reverse behavior
提问by Farsen
I have a Stackpanel One, which has some content, an Image, and a defualt hidden SubStackpanel. When clickin the Image, the image should rotate 90 degrees, and slide down the SubStackpanel. When clicking the Image again, the Image should rotate back to its original position, and the SubStackpanel should slide up to the default hidden position.
我有一个 Stackpanel One,它有一些内容、一个图像和一个默认隐藏的 SubStackpanel。单击图像时,图像应旋转 90 度,然后向下滑动 SubStackpanel。再次单击 Image 时,Image 应旋转回其原始位置,SubStackpanel 应向上滑动到默认隐藏位置。
I almost got this working, the problem is that I dont know how to use the same Trigger event, on two different Storyboard animations. So right now only the first animation on the button and the SubStackpanel occurs, everytime the Image is clicked. I′ve tried the AutoReverse property, but it fires immediately after the animation is done. This should of course only be happening when the user clicks the Image the second time.
我差点就搞定了,问题是我不知道如何在两个不同的 Storyboard 动画中使用相同的 Trigger 事件。所以现在只有按钮上的第一个动画和 SubStackpanel 发生,每次单击图像时。我试过 AutoReverse 属性,但它在动画完成后立即触发。这当然应该只在用户第二次单击图像时发生。
I would like to achieve this, only using markup.
我想实现这一点,只使用标记。
This is my currently code:
这是我目前的代码:
<Grid>
<StackPanel Grid.Row="0" Orientation="Vertical" Background="Beige" >
<StackPanel.Triggers>
<EventTrigger SourceName="ImageShowPanelTwo" RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SubPanel" Storyboard.TargetProperty="(StackPanel.Height)" From="0" To="66" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger SourceName="ImageShowPanelTwo" RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="SubPanel" Storyboard.TargetProperty="(StackPanel.Height)" From="66" To="0" Duration="0:0:0.5" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</StackPanel.Triggers>
<TextBlock>Panel One</TextBlock>
<Image Name="ImageShowPanelTwo" Width="26" Height="26" Source="ImageRotate.png" RenderTransformOrigin=".5,.5" >
<Image.RenderTransform>
<RotateTransform x:Name="AnimatedRotateTransform" Angle="0" />
</Image.RenderTransform>
<Image.Triggers>
<EventTrigger RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="0"
To="90"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="Image.MouseDown">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="90"
To="0"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Image.Triggers>
</Image>
<StackPanel Name="SubPanel" Background="LightGreen" Height="66">
<TextBlock>SubPanel</TextBlock>
<TextBlock>SubPanel</TextBlock>
</StackPanel>
</StackPanel>
</Grid>
Hope you can help :)
希望能帮到你 :)
采纳答案by Farsen
This is how I solved my problem:
这就是我解决我的问题的方法:
Created four storyboards for the Stackpanel and the arrow:
为 Stackpanel 和箭头创建了四个故事板:
<Storyboard x:Key="RotateIconUp">
<DoubleAnimation Storyboard.TargetName="IconExpand" Storyboard.TargetProperty="(TextBlock.RenderTransform).(RotateTransform.Angle)" From="0" To="90" Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="RotateIconDown">
<DoubleAnimation Storyboard.TargetName="IconExpand" Storyboard.TargetProperty="(TextBlock.RenderTransform).(RotateTransform.Angle)" From="90" To="0" Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="SlideGridDown">
<DoubleAnimation Storyboard.TargetName="GridDetails" Storyboard.TargetProperty="(Grid.Height)" From="0" To="180" Duration="0:0:0.4" />
</Storyboard>
<Storyboard x:Key="SlideGridUp">
<DoubleAnimation Storyboard.TargetName="GridDetails" Storyboard.TargetProperty="(Grid.Height)" From="180" To="0" Duration="0:0:0.4" />
</Storyboard>
Then I trigger the storyboards from codebehind when the arrow is clicked:
然后,当单击箭头时,我从代码隐藏触发故事板:
private void ExpandDetails() {
try {
if (!pm_IsExanded) {
Storyboard Storyboard = (Storyboard)FindResource("RotateIconUp");
Storyboard.Begin(this);
Storyboard = (Storyboard)FindResource("SlideGridDown");
Storyboard.Begin(this);
pm_IsExanded = true;
BorderMain.BorderBrush = pm_BrushConverter.ConvertFromString("#000000") as Brush;
} else {
Storyboard Storyboard = (Storyboard)FindResource("RotateIconDown");
Storyboard.Begin(this);
Storyboard = (Storyboard)FindResource("SlideGridUp");
Storyboard.Begin(this);
pm_IsExanded = false;
BorderMain.BorderBrush = pm_BrushConverter.ConvertFromString("#d0d0d0") as Brush;
}
} catch (Exception ee) {
GlobalResource.WriteToLog("Error in ExpandDetails", ee);
}
}
回答by Suhas Bharadwaj
Blend for Visual Studio can be used to do it in a better, simpler way, without dealing with a lot of code.
Blend for Visual Studio 可用于以更好、更简单的方式完成此操作,而无需处理大量代码。
Here is the list of steps of doing it.
这是执行此操作的步骤列表。
Step 1: Open the project in Blend for Visual Studio and in Visual Studio simultaneously.
步骤 1:同时在 Blend for Visual Studio 和 Visual Studio 中打开项目。
Step 2: In Blend, create a new storyboard around all the elements that you wish to animate with it. Let's call it "Storyboard1".
第 2 步:在 Blend 中,围绕您希望用它制作动画的所有元素创建一个新的故事板。我们称它为“Storyboard1”。


Step 3: Now, open the storyboard that we just created and click on the small arrow just beside the "+" and click on "Duplicate" in the drop down menu. Then, a new storyboard called "Storyboard1_Copy" will be created.
第 3 步:现在,打开我们刚刚创建的故事板并单击“+”旁边的小箭头,然后单击下拉菜单中的“复制”。然后,将创建一个名为“Storyboard1_Copy”的新故事板。


Step 4: Rename this new storyboard to something that you like, say, "Storyboard1_Rev".
第 4 步:将这个新故事板重命名为您喜欢的名称,例如“Storyboard1_Rev”。




Step 5: You must have guessed it by now. Select the duplicated storyboard and from the drop down menu, click on "Reverse".
第 5 步:您现在一定已经猜到了。选择复制的故事板,然后从下拉菜单中单击“反向”。


Step 6: Now you have two storyboards ready: one for animating some elements as you like and the other for reversing that sequence of animation. Just like you call a storyboard from the C# code, you can call the reversing storyboard from the same, subject to some conditions which check if the elements are already animated or not. For this, I use a bool variable, whose value is changed each time some animation occurs on a set of elements(that is, false if the elements are not already animated and true if they are).
第 6 步:现在您已经准备好两个故事板:一个用于根据您的喜好为某些元素设置动画,另一个用于反转该动画序列。就像您从 C# 代码中调用故事板一样,您也可以从相同的代码中调用反向故事板,这取决于检查元素是否已经动画化的某些条件。为此,我使用了一个 bool 变量,每次在一组元素上发生动画时都会更改其值(即,如果元素尚未动画,则为 false,如果已动画,则为 true)。
Illustration with an example:
举例说明:
I'll create an application with a simple layout. It has a button, an image and a rectangular area on the screen.
我将创建一个具有简单布局的应用程序。它在屏幕上有一个按钮、一个图像和一个矩形区域。


The idea is that, whenever you click on the button once, the image should be maximized and should be minimized back to original size when the button is clicked twice and so on. That is, the reverse animation should happen every other time the button is clicked. Here are some screenshots showing how it happens:
这个想法是,每当你点击按钮一次时,图像应该最大化,当按钮被点击两次时应该最小化回到原始大小,依此类推。也就是说,每隔一次单击按钮时就会发生反向动画。以下是一些屏幕截图,显示了它是如何发生的:










You can see that the current state of the image is shown in the button. It shows "Zoom In" when the image is in its initial small size and "Zoom Out" when it is maximized.
您可以看到图像的当前状态显示在按钮中。当图像处于初始小尺寸时显示“放大”,最大化时显示“缩小”。
And finally, here is the C# code for handling the clicks of the button:
最后,这里是处理按钮点击的 C# 代码:
bool flag = false;
private void Button_Click(object sender, RoutedEventArgs e)
{
if (!flag)
{
Button.Content = "Zoom Out";
Storyboard1.Begin();
flag = true;
}
else
{
Button.Content = "Zoom In";
Storyboard1_Rev.Begin();
flag = false;
}
}
All you have to do is have a status flag that shows the current status of the element(s) that you wish to animate and animate it(them) in forward or reverse timeline as per the value of the flag.
您所要做的就是有一个状态标志,显示您希望动画的元素的当前状态,并根据标志的值在正向或反向时间线中为其(它们)设置动画。
回答by Sheridan
Instead of trying to set the Animationusing that event, use a boolproperty to bind to instead:
不要尝试Animation使用该事件来设置,而是使用bool要绑定到的属性:
<Image Name="ImageShowPanelTwo" Width="26" Height="26" Source="ImageRotate.png"
RenderTransformOrigin=".5,.5" >
<Image.RenderTransform>
<RotateTransform x:Name="AnimatedRotateTransform" Angle="0" />
</Image.RenderTransform>
<Image.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding IsRotated}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="0"
To="90"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
<DataTrigger Binding="{Binding IsRotated}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="AnimatedRotateTransform"
Storyboard.TargetProperty="Angle"
By="90"
To="0"
Duration="0:0:0.5"
AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Image.Style>
</Image>
I trust that you can define your own boolproperty and invert it upon each MouseDownevent occurrence to complete this functionality. As it is set to truethe first Animationwill start and as it is set to falsethe second will start.
我相信您可以定义自己的bool属性并在每次MouseDown事件发生时将其反转以完成此功能。设置为true第一个Animation将启动,设置为false第二个将启动。

![wpf Windows Phone 8 - 使用绑定将字节 [] 数组加载到 XAML 图像中](/res/img/loading.gif)