Поместите раскадровку в ресурсы приложения
Мне нужно использовать одну и ту же раскадровку в нескольких местах, поэтому я поместил раскадровку внутри своего Application.Resources . Когда я пытаюсь выполнить раскадровку, единственная проблема заключается в том, что мне нужно сослаться на цель, которую я хочу оживить. Вот моя раскадровка:
<System:String x:Key="target">border2</System:String>
<Storyboard x:Key="stHeight">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="{DynamicResource target}">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="90">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
способ, которым я анимирую высоту другого объекта, путем изменения цели динамического ресурса. Я смог сделать это, когда раскадровка была в текущем окне. Но теперь, когда я хочу разместить его в ресурсах приложения, я не знаю, как ссылаться на целевое свойство.
РЕДАКТИРОВАТЬ
Решение, которое я опубликовал ранее, работает хорошо, но иногда сложно создавать сложные анимации с помощью кода. поэтому еще одно альтернативное решение, которое я разработал, заключалось в создании раскадровки со смесью выражений. поэтому я перетаскиваю случайный элемент управления в главное окно в выражении blend и создаю случайную анимацию. скажем, анимация выглядит так:
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="90"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="103"/>
</DoubleAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="grid">
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.75,0.5"/>
</PointAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="75"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
затем я копирую этот код и вставляю его в мое рабочее окно НЕ В APP.XAML.
а затем в моем коде, скажем, у меня есть:
<Border Name="brdBorder" BorderBrush="Silver" BorderThickness="1" Margin="328,104,0,0" Background="#FFE52E2E" HorizontalAlignment="Left" Width="94" Height="100" VerticalAlignment="Top" >
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
</Border>
по какой-то причине должна существовать группа преобразования, чтобы оживить объект. В любом случае, давайте предположим, что у меня есть эта граница в моем рабочем окне, и я хочу анимировать ее с помощью той же анимации, которую я создал с помощью выражения blend. что я буду делать в коде:
Storyboard sb1 = FindResource("Storyboard1") as Storyboard;
foreach (var child in sb1.Children)
{
Storyboard.SetTargetName(child, brdBorder.Name);
}
sb1.Begin(this);
и тогда я смогу оживить эту границу в моем рабочем окне. Приятной частью этого является то, что я могу применить одну и ту же анимацию к нескольким объектам (я думаю, это цель создания ресурса), проблема возникает, когда я пытаюсь поместить раскадровку в словарь ресурсов или в app.xaml. файл. когда я делаю это, C# может найти раскадровку, но свойства раскадровки доступны только для чтения, поэтому я получаю сообщение об ошибке:
Cannot set a property on object 'System.Windows.Media.Animation.DoubleAnimationUsingKeyFrames' because it is in a read-only state.
Причина, по которой я хотел сделать это, состоит в том, чтобы применить одну и ту же анимацию к нескольким объектам. Обходным решением было создать базовую анимацию с кодом, а затем более сложную анимацию, такую как функция замедления и т. Д., Сохранить ее как ресурс. Позвольте мне показать вам, что я имею в виду.
В моем файле ресурсов я разместил следующий ресурс:
<EasingDoubleKeyFrame x:Key="pleaseWork">
<EasingDoubleKeyFrame.EasingFunction >
<BackEase EasingMode="EaseOut" Amplitude="1"/>
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
В смеси Expresion вы можете создать более сложную функцию легкости. Затем с кодом позади я создам основную раскадровку:
DoubleAnimation animation = new DoubleAnimation();
animation.To = 336; // final value
//animation.From = 0;
//animation.BeginTime = TimeSpan.FromSeconds(0);
animation.Duration = new Duration(TimeSpan.FromSeconds(5)); // how much time should animation last
// here comes the magic:
// note that I can bind to EasingDoubleKeyFrame in my resource file in xaml
animation.EasingFunction = ((EasingDoubleKeyFrame)FindResource("pleaseWork")).EasingFunction; // apply the easing function
Storyboard.SetTarget(animation, groupBox1); // what object will be animated?
Storyboard.SetTargetProperty(animation, new PropertyPath(FrameworkElement.HeightProperty)); // what property will be animated
Storyboard sb = new Storyboard();
sb.Children.Add(animation);
sb.Begin();
Это позволило мне использовать одну и ту же раскадровку на нескольких объектах.
3 ответа
НАКОНЕЦ Я НАШЕЛ РЕШЕНИЕ!!!!!
Если вы помните, ошибка, которую я получил при размещении раскадровки в файле app.xaml, была:
Не удается установить свойство для объекта 'System.Windows.Media.Animation.DoubleAnimationUsingKeyFrames', поскольку он находится в состоянии только для чтения.
другими словами, я не мог изменить целевое свойство раскадровки, я мог просто его поменять. поэтому решение было изменить Storyboard.TargetName="grid"
за Storyboard.TargetName="{binding}"
Позвольте мне собрать все воедино:
step 1:
// create your custom storyboard with expression blend or xaml:
// let's say it comes out as:
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="90"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="103"/>
</DoubleAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="grid">
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.75,0.5"/>
</PointAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="grid">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="75"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
-
step 2:
// copy and paste your storyboard to your app.xaml file or to a
// resource dictionary (if you paste it in a resource dictionary do not
// forget to merge the dictionaries so that your code is able to find the
// storyboard as a resource)
<Application x:Class="FilesPro2._1.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="MainWindow.xaml">
<Application.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="{Binding}">
<EasingDoubleK
....
.....
...
etc
-
step 3
// заменить Storyboard.TargetName="grid" для Storyboard.TargetName="{Binding}". // Ваш ресурс раскадровки не должен выглядеть так:
<Application.Resources>
<Storyboard x:Key="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="{Binding}">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="90"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="{Binding}">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="103"/>
</DoubleAnimationUsingKeyFrames>
<PointAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransformOrigin)" Storyboard.TargetName="{Binding}">
<EasingPointKeyFrame KeyTime="0:0:1" Value="0.75,0.5"/>
</PointAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[2].(RotateTransform.Angle)" Storyboard.TargetName="{Binding}">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="75"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
-
step 4
//create a method to make it easy to run the same animation on multiple objects:
void runStoryboard(string storyboardName, string objectName)
{
Storyboard sb = FindResource(storyboardName) as Storyboard;
foreach (var child in sb.Children)
Storyboard.SetTargetName(child, objectName);
sb.Begin(this); // do not forget the this keyword
}
-
step 5
// start your animation with the object you wish to animate
runStoryboard("Storyboard1", brdBorder.Name);
ПРИМЕЧАНИЕ ВАЖНО:
зная, что при создании раскадровки с помощью выражения blend иногда выражение blend создает группу преобразования преобразования для элемента управления, который вы анимируете. в этом примере я, где анимация границы. и для того, чтобы эта граница была оживленной, она должна была иметь
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
Другими словами, если ваша анимация имеет дело с масштабным преобразованием, асимметричным преобразованием и т. Д., То разместите эту группу преобразования для всех объектов, которые вы планируете анимировать.
В конце концов я могу оживить:
<Border Name="brdBorder" BorderBrush="Silver" BorderThickness="1" Margin="338,6,0,0" Background="#FFE52E2E" HorizontalAlignment="Left" Width="94" Height="38" VerticalAlignment="Top">
<Border.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Border.RenderTransform>
</Border>
// AND
<Button Name="mybutton" Content="Test" Height="20" Click="mybutton_Click">
<Button.RenderTransform>
<TransformGroup>
<ScaleTransform/>
<SkewTransform/>
<RotateTransform/>
<TranslateTransform/>
</TransformGroup>
</Button.RenderTransform>
</Button>
AS:
runStoryboard("Storyboard1", brdBorder.Name);
runStoryboard("Storyboard1", mybutton.Name);
Вам не нужно нигде ссылаться на цель, вы можете просто создать ее локально, это одна из замечательных функций динамического поиска ресурса, например
<!-- No more target here! -->
<Application.Resources>
<Storyboard x:Key="SB_Height" x:Shared="False">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(FrameworkElement.Height)"
Storyboard.TargetName="{DynamicResource AnimationTarget}">
<EasingDoubleKeyFrame KeyTime="0:0:1" Value="90">
<EasingDoubleKeyFrame.EasingFunction>
<CircleEase EasingMode="EaseOut" />
</EasingDoubleKeyFrame.EasingFunction>
</EasingDoubleKeyFrame>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Application.Resources>
<!-- Somewhere else... -->
<Button Name="mybutton" Content="Test" Height="20">
<Button.Resources>
<sys:String x:Key="AnimationTarget">mybutton</sys:String>
</Button.Resources>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<BeginStoryboard Storyboard="{StaticResource SB_Height}"/>
</EventTrigger>
</Button.Triggers>
</Button>
Для
Приложение для Windows Phone 8.1
Я столкнулся с той же проблемой и добавляю множество решений для достижения этой цели.
Это мой файл App.xaml
<Application.Resources>
<ResourceDictionary>
<Storyboard x:Key="ShowMenuAnimationKey">
<DoubleAnimation
Storyboard.TargetName="{Binding}" //this is important
Storyboard.TargetProperty="(Canvas.Left)"
From="0" To="400" Duration="0:0:1">
</DoubleAnimation>
</Storyboard>
</ResourceDictionary>
</Application.Resources>
На моей странице у меня есть что-то вроде этого (page.xaml)
<Grid x:Name="ViewPanel"
Canvas.Left="0"
Canvas.ZIndex="1">
//Etc ....
</Grid>
Теперь вы привязываете этот метод к событию (нажатие кнопки или что-то еще)
page.xaml.cs
private void MenuPanel_OnTap(object sender, GestureEventArgs e)
{
Storyboard sb = App.Current.Resources["ShowMenuAnimationKey"] as Storyboard;
sb.Stop();
Storyboard.SetTarget(sb, ViewPanel);
sb.Begin();
}
Я надеюсь, что это поможет!