我正在寻找在ControlTemplate
中包含的控件上启动动画的代码背后的方法。在我的应用程序中,我有从ObservableCollection
:创建的自定义模板按钮(扮演菜单角色)
主菜单视图模型:
/// <summary>
/// Menu items list
/// </summary>
private ObservableCollection<MenuItem> _items;
....
/// <summary>
/// Menu items list property
/// </summary>
public ObservableCollection<MenuItem> Items
{
get { return _items; }
set { _items = value; }
}
主菜单视图:
<UserControl x:Class="OfficeTourismeBrantome.Views.MainMenuView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="800" d:DesignWidth="300">
<UserControl.Resources>
<Style x:Key="MenuItemButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="60" />
<Setter Property="FontFamily" Value="Segoe" />
<Setter Property="FontWeight" Value="UltraLight" />
<Setter Property="Foreground" Value="#FFEBEDEA" />
<!--<Setter Property="Height" Value="{Binding MenuLayout.MenuItemSize.Height}" />-->
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Name="themeSelectionAnimation">
<DoubleAnimation
Storyboard.TargetName="coloredRectangle"
Storyboard.TargetProperty="Width"
From="30.0"
To="250.0"
Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
<Canvas HorizontalAlignment="Stretch" ClipToBounds="False" >
<ContentPresenter Canvas.Left="{Binding MenuLayout.MenuItemLeftMargin}" HorizontalAlignment="Center"
VerticalAlignment="Center" Canvas.ZIndex="1"/>
<TextBlock
Text="{Binding SecondaryText}"
Canvas.Top="50"
Canvas.Left="10"
FontSize="30"
FontWeight="ExtraLight"
FontStyle="Italic"
Canvas.ZIndex="1"
/>
<Rectangle
Canvas.Top="30"
Canvas.Left="10"
Name="coloredRectangle"
Width="30"
Height="10"
Canvas.ZIndex="0"
Fill="{Binding Color}"/>
</Canvas>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Storyboard x:Key="themeUnselectionAnimation">
<DoubleAnimation
Storyboard.TargetProperty="Width"
From="250.0"
To="30.0"
Duration="0:0:0.15" />
</Storyboard>
</UserControl.Resources>
<ItemsControl Name="menuButtonContainer" ItemsSource="{Binding Items}" Margin="{Binding MenuLayout.MenuMargin}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Style="{StaticResource ResourceKey=MenuItemButtonStyle}"
Margin="{Binding ElementName=menuButtonContainer,
Path=DataContext.MenuLayout.MenuItemMargin}"
Height="{Binding ElementName=menuButtonContainer,
Path=DataContext.MenuLayout.MenuItemSize.Height}"
Content="{Binding Text}"
Command="{Binding ElementName=menuButtonContainer,
Path=DataContext.ChangeThemeCommand}"
CommandParameter="{Binding Id}"
/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</UserControl>
正如你在上面的代码中看到的,我得到了一个按钮点击时自动触发的动画。当点击集合中的另一个按钮(选择了另一个菜单项)时,我想反向播放。要播放的动画是名为themeUnselectionAnimation的动画。
第一个问题:是否有一种方法只能在XAML中实现?我不确定,因为需要按下另一个按钮才能触发它。
以下是我的想法:
- 在
Button
(这是我的菜单项)命令操作中,发送一条消息让订阅者知道菜单项正在更改 - 在
MainMenuView
代码后面注册 - 从那里启动动画
到目前为止,我的问题是设置动画的目标控件。为此,我需要在ControlTemplate
中找到名为coloredRectangle
的Rectangle
。如何做到这一点?
下面是我对应上述步骤的代码:
步骤1:发送消息(我使用的是MVVM Light框架)
/// <summary>
/// Delegates that handles theme change process and tasks
/// </summary>
/// <param name="themeId">the new active theme</param>
private void ChangeTheme(int themeId)
{
// Set current active theme as inactive, if one is selected.
// Exception use because of Single implementation that throw an InvalidOperationException if not item is found
try
{
MenuItem currentTheme = Items.Single(x => x.IsActive == true);
// Check if this is current theme. If it is, we do nothing.
if(currentTheme.Id == themeId)
return;
// If current theme is set and new theme id is not the same, disable the old one
currentTheme.IsActive = false;
// Set new theme as active
Items.Single(x => x.Id == themeId).IsActive = true;
// Finally, launch unselection animation
// Send message and register to it in view code behind
// Create inner message
ThemeChangeNotification innerMessage = new ThemeChangeNotification();
innerMessage.NewThemeId = themeId;
innerMessage.OldThemeId = currentTheme.Id;
NotificationMessage<ThemeChangeNotification> message =
new NotificationMessage<ThemeChangeNotification>(innerMessage, "");
// Send message
Messenger.Default.Send(message);
}
catch (InvalidOperationException exception)
{
// Set first theme selection as active
Items.Single(x => x.Id == themeId).IsActive = true;
}
}
步骤2:注册到消息
Messenger.Default.Register<NotificationMessage<ThemeChangeNotification>>(this, ChangeThemeAnimation);
步骤3:从索引/id到达按钮并启动动画(不工作)
/// <summary>
/// Theme change message delegate
/// </summary>
/// <param name="e">The ThemeChangeNotification message</param>
private void ChangeThemeAnimation(NotificationMessage<ThemeChangeNotification> message)
{
var buttonTheme = menuButtonContainer.ItemContainerGenerator.ContainerFromIndex(message.Content.OldThemeId) as FrameworkElement;
var rectangle = buttonTheme.FindName("coloredRectangle") as Rectangle;
Storyboard sb = this.FindResource("themeUnselectionAnimation") as Storyboard;
Storyboard.SetTarget(sb, rectangle);
sb.Begin();
}
非常感谢你的回答!
当然,您可以在第一个使用其他Storyboard
的Style
的基础上创建另一个CCD_8。。。则可以将反向CCD_ 10应用于要启动该CCD_
<Style x:Key="ReverseMenuItemButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="60" />
<Setter Property="FontFamily" Value="Segoe" />
<Setter Property="FontWeight" Value="UltraLight" />
<Setter Property="Foreground" Value="#FFEBEDEA" />
<Setter Property="HorizontalContentAlignment" Value="Right" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<ControlTemplate.Triggers>
<EventTrigger RoutedEvent="Button.Click">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard Name="themeUnselectionAnimation">
<DoubleAnimation
Storyboard.TargetName="coloredRectangle"
Storyboard.TargetProperty="Width"
From="30.0"
To="250.0"
Duration="0:0:0.3" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</ControlTemplate.Triggers>
...
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
我必须完全诚实。。。我不完全理解你的问题,所以如果这不能回答它,那么你似乎也想知道如何从视图模型启动Storyboard
。在这种情况下,您只需要一个bool
属性,该属性将在视图模型中设置为true
时启动动画。您可以使用DataTrigger.EnterActions
:
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding SomeBooleanPropertyInViewModel}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard ... />
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
更新>>>
再次。。。我还是不知道你在追求什么。。。我建议在发布另一个问题之前,先练习一下你的提问技巧。然而,我可以计算出这么多:
您收到一个TargetName无法用于Style Setter错误,并且您希望将
coloredRectangle
元素作为目标。
此错误的常见修复方法只是将Trigger
移动到您试图定位的元素。因此,请尝试以下操作:
<Rectangle Canvas.Top="30" Canvas.Left="10" Name="coloredRectangle" ... >
<Rectangle.Style>
<Style>
<Style.Triggers>
<DataTrigger Binding="{Binding SomeBooleanProperty}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard ... />
</BeginStoryboard>
</DataTrigger.EnterActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Rectangle.Style>
</Rectangle>