質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.04%

[WPF]コードビハインドでStoryboard.TargetPropertyを設定することは可能でしょうか

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 434

score 25

やりたいこと

コードビハインドで条件によって再生するアニメーションを変えたいです。
StoryBoardを複数用意するのではなく、一つのStoryBoardだけをxamlに用意しておき、コードビハインドで条件に従ってTargetPropertyのみを変えるような形でアニメーションを切り替えることは可能でしょうか。

例として用意した下のサンプルプログラムでは、「さいころを振る」ボタンを押すと変数DEMEがランダムに1~6の値を取ります。
また、StoryBoardにはTargetPropertyに設定した目がジャンプするアニメーションを作成し、「さいころを振る」ボタンを押したときに再生されるようにしています。
たとえばStoryboard.TargetProperty="One"とすることで、「さいころを振る」ボタンを押したときに「1」がジャンプします。

Storyboard.TargetPropertyにDEME_NAMEプロパティをBindingする(Storyboard.TargetName="{Binding Path=DEME_NAME}")ことで、さいころの出目に応じた番号をジャンプさせることはできないかと試してみたのですが、エラーとなりました。(System.InvalidOperationException)
TargetPropertyを、DEMEが1のときはONE、2のときはTwo...といったようにコードビハインドで変化させることはできないでしょうか。

サンプルコード

「さいころを振る」ボタンを押したときに「1」がジャンプするパターンのコードを記載します。

using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media.Animation;


namespace Saikoro
{
    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        Hoge hoge = new Hoge();

        public MainWindow()
        {
            InitializeComponent();
            DataContext = hoge;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            hoge.Shake();
            var sb = FindResource("Jump") as Storyboard;
            BeginStoryboard(sb);
        }
    }

    public class Hoge : INotifyPropertyChanged
    {

        #region INotifyPropertyChanged の実装
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaiseProeprtyChanged(string propertyName)
        {
            var h = this.PropertyChanged;
            if (h != null) h(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion INotifyPropertyChanged の実装
        public int _DEME;
        public int DEME
        {
            set { _DEME = value; }
            get { return _DEME; }
        }

        //Storyboard.TargetPropertyにBindingするために用意したプロパティ。
        //現状ではBindingするとエラーが出るため使っていない。
        public string DEME_NAME 
        {
            get
            {
                switch (_DEME)
                {
                    case 1:
                        return "One";
                    case 2:
                        return "Two";
                    case 3:
                        return "Three";
                    case 4:
                        return "Four";
                    case 5:
                        return "Five";
                    case 6:
                        return "Six";
                    default:
                        return "One";
                }
            }
        }

        private static readonly Random rnd = new Random();

        public void Shake()
        {
            DEME = rnd.Next(1, 7);//1から6のランダムな出目
            RaiseProeprtyChanged("DEME");
        }
    }
}
<Window x:Class="Saikoro.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"
        xmlns:local="clr-namespace:Saikoro"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="300">
    <Window.Resources>
        <Storyboard x:Key="Jump">
       <!--Storyboard.TargetName="{Binding Path=DEME_NAME}"とするとエラーになる-->
            <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="One">
                <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-20"/>
                <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0"/>
            </DoubleAnimationUsingKeyFrames>
        </Storyboard>
    </Window.Resources>
    <Canvas>
        <Button Click="Button_Click" Content="さいころを振る" Canvas.Left="107.334" Canvas.Top="37.333" Width="75" Height="25"/>
        <Grid Width="292" Height="286" Canvas.Top="133">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition/>
                <ColumnDefinition/>
            </Grid.ColumnDefinitions>
            <TextBlock x:Name="One"   Grid.Column="0" Grid.Row="0" TextWrapping="Wrap" Text="1" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="36" RenderTransformOrigin="0.5,0.5">
                <TextBlock.RenderTransform>
                    <TransformGroup>
                        <ScaleTransform/>
                        <SkewTransform/>
                        <RotateTransform/>
                        <TranslateTransform/>
                    </TransformGroup>
                </TextBlock.RenderTransform>
            </TextBlock>
            <TextBlock x:Name="Two"   Grid.Column="1" Grid.Row="0" TextWrapping="Wrap" Text="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="36"/>
            <TextBlock x:Name="Three" Grid.Column="0" Grid.Row="1" TextWrapping="Wrap" Text="3" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="36"/>
            <TextBlock x:Name="Four"  Grid.Column="1" Grid.Row="1" TextWrapping="Wrap" Text="4" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="36"/>
            <TextBlock x:Name="Five"  Grid.Column="0" Grid.Row="2" TextWrapping="Wrap" Text="5" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="36"/>
            <TextBlock x:Name="Six"   Grid.Column="1" Grid.Row="2" TextWrapping="Wrap" Text="6" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="36"/>
        </Grid>
        <TextBlock Canvas.Left="121.333" TextWrapping="Wrap" Text="{Binding Path=DEME}" Canvas.Top="90.333" Height="26.627" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="24" TextAlignment="Center"/>
    </Canvas>
</Window>

実行時の画面

イメージ説明

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+1

RenderTransformOneにしか付いていないので、ほかの目が出たときにエラーになります。
全部に付ければ想定通りに動きます。

<Window
  x:Class="Questions300589.MainWindow"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Width="300"
  Height="450">
  <Window.Resources>
    <Storyboard x:Key="Jump">
      <DoubleAnimationUsingKeyFrames Storyboard.TargetName="{Binding DEME_NAME}" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)">
        <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-20" />
        <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" />
      </DoubleAnimationUsingKeyFrames>
    </Storyboard>

    <Style TargetType="{x:Type TextBlock}">
      <Setter Property="HorizontalAlignment" Value="Center" />
      <Setter Property="VerticalAlignment" Value="Center" />
      <Setter Property="FontSize" Value="36" />
      <Setter Property="RenderTransform">
        <Setter.Value>
          <TranslateTransform />
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Resources>
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
      <RowDefinition Height="3*" />
    </Grid.RowDefinitions>
    <Button
      HorizontalAlignment="Center"
      VerticalAlignment="Center"
      Click="Button_Click"
      Content="さいころを振る" />

    <TextBlock FontSize="24" Text="{Binding DEME}" Grid.Row="1" />

    <UniformGrid Grid.Row="2" Columns="2">
      <TextBlock x:Name="One" Text="1" />
      <TextBlock x:Name="Two" Text="2" />
      <TextBlock x:Name="Three" Text="3" />
      <TextBlock x:Name="Four" Text="4" />
      <TextBlock x:Name="Five" Text="5" />
      <TextBlock x:Name="Six" Text="6" />
    </UniformGrid>
  </Grid>
</Window>
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Media.Animation;

namespace Questions300589
{
    public partial class MainWindow : Window
    {
        private readonly Hoge hoge = new Hoge();
        private readonly Storyboard sb;

        public MainWindow()
        {
            InitializeComponent();
            DataContext = hoge;
            sb = FindResource("Jump") as Storyboard;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            hoge.Shake();
            BeginStoryboard(sb);
        }
    }

    public class Hoge : INotifyPropertyChanged
    {
        private static readonly Random rnd = new Random();

        public int DEME { get; private set; }

        public string DEME_NAME
        {
            get
            {
                switch(DEME)
                {
                    default:
                    case 1: return "One";
                    case 2: return "Two";
                    case 3: return "Three";
                    case 4: return "Four";
                    case 5: return "Five";
                    case 6: return "Six";
                }
            }
        }

        public void Shake()
        {
            DEME = rnd.Next(1, 7);
            RaiseProeprtyChanged(nameof(DEME));
            RaiseProeprtyChanged(nameof(DEME_NAME));
        }

        #region INotifyPropertyChanged の実装
        public event PropertyChangedEventHandler PropertyChanged;
        private void RaiseProeprtyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        #endregion 
    }
}

xamlが長くなりそうだったのでだいぶ変えてしまいましたが、元の形でもOKです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/10/28 10:52

    そういうことでしたか、ありがとうございます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る