none
ButtonかToggleButtonかでアニメーションを切り替えるコントロールテンプレート

    質問

  • ButtonBaseをターゲットとするコントロールテンプレートをつくり,Button 用のスタイルと ToggleButton 用のスタイルからそれぞれこのテンプレートを使うことを考えています。

    テンプレートを適用したコントロールが Button か ToggleButton かにより,次のように再生するアニメーションを使い分けたいと考えています。

    1. Button がクリックされた場合または ToggleButton が Uncheck された場合はアニメーションAを再生する。
    2. ToggleButton が Check された場合はアニメーションBを再生する。

    次のようにテンプレートのトリガを設定したのですが,どうやら Click という RoutedEvent は Button と ToggleButton 双方の親クラスである ButtonBase に属するものらしく,上記のアニメーションBが再生されずアニメーションAのみ優先されて再生されてしまいます。

    <ControlTemplate.Triggers> <!-- 中略 --> <EventTrigger RoutedEvent="Button.Click"> <BeginStoryboard Storyboard="{DynamicResource StoryboardA}"/> </EventTrigger> <EventTrigger RoutedEvent="ToggleButton.Unchecked"> <BeginStoryboard Storyboard="{DynamicResource StoryboardA}"/> </EventTrigger> <EventTrigger RoutedEvent="ToggleButton.Checked"> <BeginStoryboard Storyboard="{DynamicResource StoryboardB}"/> </EventTrigger> </ControlTemplate.Triggers>

    上記のようなアニメーションの使い分けは可能なのでしょうか?

    可能な場合,どのようにすればよいのでしょうか?

    最悪,FreezableCollection を用いてスタイルに Behavior を添付し,Behavior からアニメーションを再生する手も考えていますが,できるだけXAMLで完結できればと考えています。

    教えていただけますと幸いです。


    2018年12月13日 9:50

回答

  • こんな

    <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
            Title="MainWindow" SizeToContent="WidthAndHeight">
        <Window.Resources>
    
            <Style x:Key="ButtonStyle1" TargetType="{x:Type ButtonBase}">
                <Setter Property="Width" Value="100" />
                <Setter Property="Height" Value="100" />
                <Setter Property="HorizontalAlignment" Value="Center" />
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="HorizontalContentAlignment" Value="Center" />
                <Setter Property="VerticalContentAlignment" Value="Center" />
    
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ButtonBase}">
                            <ControlTemplate.Resources>
                                <Storyboard x:Key="storyClick">
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dot" Storyboard.TargetProperty="Fill" FillBehavior="HoldEnd">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                <SolidColorBrush Color="LightGreen" />
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
    
                                    <DoubleAnimation From="0" To="1" Duration="0:0:1" Storyboard.TargetName="dot" Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
    
                                <Storyboard x:Key="storyUnchecked">
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dot" Storyboard.TargetProperty="Fill" FillBehavior="HoldEnd">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0"  >
                                            <DiscreteObjectKeyFrame.Value>
                                                <SolidColorBrush Color="Red" />
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
    
                                    <DoubleAnimation From="1" To="0" Duration="0:0:1" Storyboard.TargetName="dot" Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
    
                                <Storyboard x:Key="storyChecked">
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dot" Storyboard.TargetProperty="Fill" FillBehavior="HoldEnd">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                <SolidColorBrush Color="Red" />
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
    
                                    <DoubleAnimation From="0" To="1" Duration="0:0:1" Storyboard.TargetName="dot" Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
                            </ControlTemplate.Resources>
                            <Grid>
                                <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent">
                                    <Grid>
                                        <Ellipse x:Name="dot" Width="50" Height="50" Fill="Transparent" StrokeThickness="3" />
                                        <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                    </Grid>
                                </Border>
    
                                <StackPanel IsHitTestVisible="False" Visibility="Collapsed">
                                    <ContentControl x:Name="dummyIsChecked" Content="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=IsChecked,FallbackValue=Button}" />
                                    <ContentControl x:Name="dummyIsToggle" Tag="false" Content="{Binding RelativeSource={RelativeSource Mode=Self},Path=Tag}"/>
                                    <ContentControl x:Name="dummyIsClick" Tag="false" Content="{Binding RelativeSource={RelativeSource Mode=Self},Path=Tag}" />
                                </StackPanel>
                            </Grid>
    
    
                            <ControlTemplate.Triggers>
                                <DataTrigger Binding="{Binding Path=IsThreeState,RelativeSource={RelativeSource Mode=Self}}" Value="true">
                                    <DataTrigger.Setters>
                                        <Setter  TargetName="dummyIsToggle" Property="Tag" Value="true" />
                                    </DataTrigger.Setters>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Path=IsThreeState,RelativeSource={RelativeSource Mode=Self}}" Value="false">
                                    <DataTrigger.Setters>
                                        <Setter  TargetName="dummyIsToggle" Property="Tag" Value="true" />
                                    </DataTrigger.Setters>
                                </DataTrigger>
    
                                <EventTrigger RoutedEvent="Button.Click" >
                                    <EventTrigger.Actions>
                                        <BeginStoryboard>
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dummyIsClick" Storyboard.TargetProperty="Tag" FillBehavior="Stop" >
                                                    <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="true" />
                                                    <DiscreteObjectKeyFrame KeyTime="0:0:0.000001" Value="false" />
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger.Actions>
                                </EventTrigger>
    
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding ElementName=dummyIsToggle,Path=Tag}" Value="false"/>
                                        <Condition Binding="{Binding ElementName=dummyIsClick,Path=Tag}" Value="true"/>
                                    </MultiDataTrigger.Conditions>
                                    <MultiDataTrigger.EnterActions>
                                        <BeginStoryboard Storyboard="{StaticResource ResourceKey=storyClick}" />
                                    </MultiDataTrigger.EnterActions>
                                </MultiDataTrigger>
    
                                <!--********************************************** -->
    
                                <EventTrigger RoutedEvent="ToggleButton.Unchecked"  >
                                    <EventTrigger.Actions>
                                        <BeginStoryboard Storyboard="{StaticResource ResourceKey=storyUnchecked}" />
                                    </EventTrigger.Actions>
                                </EventTrigger>
    
                                <EventTrigger RoutedEvent="ToggleButton.Checked">
                                    <EventTrigger.Actions>
                                        <BeginStoryboard Storyboard="{StaticResource ResourceKey=storyChecked}" />
                                    </EventTrigger.Actions>
                                </EventTrigger>
    
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Resources>
    
        <Grid>
            <UniformGrid Columns="2">
                <Button Style="{DynamicResource ButtonStyle1}" Content="Button"/>
    
                <CheckBox Style="{DynamicResource ButtonStyle1}" Content="CheckBox"/>
            </UniformGrid>
        </Grid>
    </Window>

    #XAML のみという制限がなければもっと楽なんだけど


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2018年12月20日 3:26

すべての返信

  • 菜乃曽富斗さん、こんにちは。フォーラムオペレーターのHarukaです。
    MSDNフォーラムにご投稿くださいましてありがとうございます。

    ご説明によると、Buttonには2つのスタイルを使用したく、
    1つはButtonスタイルで、もう1つはTooggleButtonスタイルです。
    Buttonをチェックされた場合とToggleButtonをUncheckされた場合は、アニメーションAを再生し、
    ToggleButtonがチェックされている場合はアニメーションBを再生するとのことがわかります。

    ButtonBaseのコントロールテンプレートやスタイルを動的に変更することをお勧めします。以下のスレッドを見てください:

    https://stackoverflow.com/questions/3863799/how-to-change-button-template-dynamically-wpf

    https://stackoverflow.com/questions/22234236/wpf-mvvm-change-static-resource-style-dynamically

    うぞよろしくお願いします。


    ~ 参考になった投稿には回答としてマークの設定にご協力ください ~
    MSDN Community Support Haruka

    2018年12月19日 5:50
    モデレータ
  • こんな

    <Window x:Class="WpfApp1.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
            Title="MainWindow" SizeToContent="WidthAndHeight">
        <Window.Resources>
    
            <Style x:Key="ButtonStyle1" TargetType="{x:Type ButtonBase}">
                <Setter Property="Width" Value="100" />
                <Setter Property="Height" Value="100" />
                <Setter Property="HorizontalAlignment" Value="Center" />
                <Setter Property="VerticalAlignment" Value="Center" />
                <Setter Property="HorizontalContentAlignment" Value="Center" />
                <Setter Property="VerticalContentAlignment" Value="Center" />
    
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ButtonBase}">
                            <ControlTemplate.Resources>
                                <Storyboard x:Key="storyClick">
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dot" Storyboard.TargetProperty="Fill" FillBehavior="HoldEnd">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                <SolidColorBrush Color="LightGreen" />
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
    
                                    <DoubleAnimation From="0" To="1" Duration="0:0:1" Storyboard.TargetName="dot" Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
    
                                <Storyboard x:Key="storyUnchecked">
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dot" Storyboard.TargetProperty="Fill" FillBehavior="HoldEnd">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0"  >
                                            <DiscreteObjectKeyFrame.Value>
                                                <SolidColorBrush Color="Red" />
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
    
                                    <DoubleAnimation From="1" To="0" Duration="0:0:1" Storyboard.TargetName="dot" Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
    
                                <Storyboard x:Key="storyChecked">
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dot" Storyboard.TargetProperty="Fill" FillBehavior="HoldEnd">
                                        <DiscreteObjectKeyFrame KeyTime="0:0:0" >
                                            <DiscreteObjectKeyFrame.Value>
                                                <SolidColorBrush Color="Red" />
                                            </DiscreteObjectKeyFrame.Value>
                                        </DiscreteObjectKeyFrame>
                                    </ObjectAnimationUsingKeyFrames>
    
                                    <DoubleAnimation From="0" To="1" Duration="0:0:1" Storyboard.TargetName="dot" Storyboard.TargetProperty="Opacity" />
                                </Storyboard>
                            </ControlTemplate.Resources>
                            <Grid>
                                <Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent">
                                    <Grid>
                                        <Ellipse x:Name="dot" Width="50" Height="50" Fill="Transparent" StrokeThickness="3" />
                                        <ContentPresenter x:Name="contentPresenter" Focusable="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                                    </Grid>
                                </Border>
    
                                <StackPanel IsHitTestVisible="False" Visibility="Collapsed">
                                    <ContentControl x:Name="dummyIsChecked" Content="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},Path=IsChecked,FallbackValue=Button}" />
                                    <ContentControl x:Name="dummyIsToggle" Tag="false" Content="{Binding RelativeSource={RelativeSource Mode=Self},Path=Tag}"/>
                                    <ContentControl x:Name="dummyIsClick" Tag="false" Content="{Binding RelativeSource={RelativeSource Mode=Self},Path=Tag}" />
                                </StackPanel>
                            </Grid>
    
    
                            <ControlTemplate.Triggers>
                                <DataTrigger Binding="{Binding Path=IsThreeState,RelativeSource={RelativeSource Mode=Self}}" Value="true">
                                    <DataTrigger.Setters>
                                        <Setter  TargetName="dummyIsToggle" Property="Tag" Value="true" />
                                    </DataTrigger.Setters>
                                </DataTrigger>
                                <DataTrigger Binding="{Binding Path=IsThreeState,RelativeSource={RelativeSource Mode=Self}}" Value="false">
                                    <DataTrigger.Setters>
                                        <Setter  TargetName="dummyIsToggle" Property="Tag" Value="true" />
                                    </DataTrigger.Setters>
                                </DataTrigger>
    
                                <EventTrigger RoutedEvent="Button.Click" >
                                    <EventTrigger.Actions>
                                        <BeginStoryboard>
                                            <Storyboard>
                                                <ObjectAnimationUsingKeyFrames Storyboard.TargetName="dummyIsClick" Storyboard.TargetProperty="Tag" FillBehavior="Stop" >
                                                    <DiscreteObjectKeyFrame KeyTime="0:0:0" Value="true" />
                                                    <DiscreteObjectKeyFrame KeyTime="0:0:0.000001" Value="false" />
                                                </ObjectAnimationUsingKeyFrames>
                                            </Storyboard>
                                        </BeginStoryboard>
                                    </EventTrigger.Actions>
                                </EventTrigger>
    
                                <MultiDataTrigger>
                                    <MultiDataTrigger.Conditions>
                                        <Condition Binding="{Binding ElementName=dummyIsToggle,Path=Tag}" Value="false"/>
                                        <Condition Binding="{Binding ElementName=dummyIsClick,Path=Tag}" Value="true"/>
                                    </MultiDataTrigger.Conditions>
                                    <MultiDataTrigger.EnterActions>
                                        <BeginStoryboard Storyboard="{StaticResource ResourceKey=storyClick}" />
                                    </MultiDataTrigger.EnterActions>
                                </MultiDataTrigger>
    
                                <!--********************************************** -->
    
                                <EventTrigger RoutedEvent="ToggleButton.Unchecked"  >
                                    <EventTrigger.Actions>
                                        <BeginStoryboard Storyboard="{StaticResource ResourceKey=storyUnchecked}" />
                                    </EventTrigger.Actions>
                                </EventTrigger>
    
                                <EventTrigger RoutedEvent="ToggleButton.Checked">
                                    <EventTrigger.Actions>
                                        <BeginStoryboard Storyboard="{StaticResource ResourceKey=storyChecked}" />
                                    </EventTrigger.Actions>
                                </EventTrigger>
    
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </Window.Resources>
    
        <Grid>
            <UniformGrid Columns="2">
                <Button Style="{DynamicResource ButtonStyle1}" Content="Button"/>
    
                <CheckBox Style="{DynamicResource ButtonStyle1}" Content="CheckBox"/>
            </UniformGrid>
        </Grid>
    </Window>

    #XAML のみという制限がなければもっと楽なんだけど


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2018年12月20日 3:26
  • > ButtonBaseのコントロールテンプレートやスタイルを動的に変更することをお勧めします。以下のスレッドを見てください:

    教えていただきありがとうございます。

    返信が遅くなりまして申し訳ございません。

    XAMLで完結しない方法が今回の場合お勧めということでしょうか。

    2019年3月5日 23:38
  • ご回答ありがとうございます。

    返信が遅くなりまして申し訳ございません。

    クリックされた瞬間に、EventTrigger内でクリック用のDataTriggerが発生する状況を作り出すのがミソなのですね。

    教えていただきありがとうございます。

    仰るとおり、XAMLのみという制限が無ければもっと楽になりそうだということが実感できました。

    開発効率も考えてつくりかたを検討したいと思います。

    2019年3月6日 1:00