に含まれるコントロールでアニメーションをコード ビハインドで起動する方法を探していControlTemplateます。私のアプリでは、次のものから作成されたカスタム テンプレート ボタン (メニューの役割を果たします) がありますObservableCollection。
MainMenuViewModel :
/// <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; }
}
MainMenuView :
<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コード ビハインドで登録します。- そこからアニメーションを起動します。
これまでの問題は、アニメーションのターゲット コントロールを設定することです。Rectangleそのためには、 で指定さcoloredRectangleれたを見つける必要がありますControlTemplate。どうやってするか ?
以下は、上記の手順に対応する私のコードです。
ステップ 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();
}
ご回答ありがとうございます。