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

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

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

Q&A

解決済

1回答

1072閲覧

C# WPF ResourceDictionaryに登録されたStoryboardのイベントが発生しない

Hottopia

総合スコア16

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

WPF

Windows Presentation Foundation (WPF) は、魅力的な外観のユーザー エクスペリエンスを持つ Windows クライアント アプリケーションを作成するための次世代プレゼンテーション システムです

1グッド

0クリップ

投稿2023/01/30 07:27

編集2023/01/31 07:23

前提

C# (WPF)に関する質問です。
ResourceDictionaryに定義したStoryboardのComletedイベントを受け取って処理をしたく、以下のようなコードを組みました。
しかしイベントが発生せず、原因がわからないため質問しました。

該当のソースコード

MainWindow.xaml.cs

1namespace Sample 2{ 3 /// <summary> 4 /// Interaction logic for MainWindow.xaml 5 /// </summary> 6 public partial class MainWindow : Window 7 { 8 public MainWindow() 9 { 10 InitializeComponent(); 11 } 12 13 private void Page_Loaded(object sender, RoutedEventArgs e) 14 { 15 var sb = FindResource("SampleStoryboard") as Storyboard; 16 sb.Completed += Sb_Completed; 17 BeginStoryboard(sb); 18 } 19 20 private void Sb_Completed(object sender, EventArgs e) 21 { 22 Debug.WriteLine("イベント発生"); 23 } 24 25 } 26}

MainWindow.xaml

1<Window x:Class="Sample.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 4 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 5 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 6 xmlns:gif="http://wpfanimatedgif.codeplex.com" 7 xmlns:local="clr-namespace:Sample" 8 mc:Ignorable="d" 9 Title="MainWindow" Height="768" Width="1024"> 10 11 <Window.Background> 12 <ImageBrush ImageSource="/resources/bgimage/bgImage1.jpg" /> 13 </Window.Background> 14 <Window.Resources> 15 <ResourceDictionary> 16 <ResourceDictionary.MergedDictionaries> 17 <ResourceDictionary Source="AnimationDictionary.xaml"/> 18 </ResourceDictionary.MergedDictionaries> 19 </ResourceDictionary> 20 </Window.Resources> 21 <Window.Resources> 22 <ResourceDictionary> 23 <ResourceDictionary.MergedDictionaries> 24 <ResourceDictionary Source="SampleDictionary.xaml"/> 25 </ResourceDictionary.MergedDictionaries> 26 </ResourceDictionary> 27 </Window.Resources> 28 29 <Canvas> 30 <MediaElement x:Name = "media"/> 31 <Canvas x:Name="ObjectLayer"> 32 <Image x:Name="Object" 33 Source="object.png" 34 Height="349" Width="301" 35 Canvas.Left="374" Canvas.Top="284" 36 RenderTransformOrigin="0.5,0.5"> 37 <Image.RenderTransform> 38 <TransformGroup> 39 <ScaleTransform/> 40 </TransformGroup> 41 </Image.RenderTransform> 42 </Image> 43 </Canvas> 44 45 <Canvas x:Name="CharaLayer" 46 d:Visibility="Visible" 47 Height="768" Width="1024" 48 Background="Transparent"> 49 <Image x:Name="Char1" 50 Source="char1.png" 51 Height="350" Canvas.Left="9" Canvas.Top="414" HorizontalAlignment="Center" VerticalAlignment="Top"/> 52 <Image x:Name="Char2" 53 Source="char2.png" 54 Height="350" Canvas.Left="767" Canvas.Top="414" HorizontalAlignment="Left" VerticalAlignment="Center"/> 55 </Canvas> 56 </Canvas> 57</Window> 58

ResourceDictionary.xaml

1<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 2 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> 3 4 <Storyboard x:Key="SampleStoryboard"> 5 <!-- Objectに画像をセット --> 6 <ObjectAnimationUsingKeyFrames Storyboard.TargetName="Object" Storyboard.TargetProperty="Source"> 7 <DiscreteObjectKeyFrame KeyTime="0"> 8 <DiscreteObjectKeyFrame.Value> 9 <BitmapImage UriSource="image.png"/> 10 </DiscreteObjectKeyFrame.Value> 11 </DiscreteObjectKeyFrame> 12 </ObjectAnimationUsingKeyFrames> 13 14 <!-- キャラクターフェードイン --> 15 <ObjectAnimationUsingKeyFrames Storyboard.TargetName="CharaLayer" Storyboard.TargetProperty="Visibility"> 16 <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Visible}"/> 17 </ObjectAnimationUsingKeyFrames> 18 <DoubleAnimationUsingKeyFrames Storyboard.TargetName="CharaLayer" 19 Storyboard.TargetProperty="(UIElement.Opacity)"> 20 <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> 21 <EasingDoubleKeyFrame KeyTime="00:00:01" Value="1"> 22 <EasingDoubleKeyFrame.EasingFunction> 23 <QuarticEase EasingMode="EaseIn"/> 24 </EasingDoubleKeyFrame.EasingFunction> 25 </EasingDoubleKeyFrame> 26 </DoubleAnimationUsingKeyFrames> 27 28 <!-- Objectのアピールイン --> 29 <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Object" Storyboard.TargetProperty="(UIElement.Opacity)"> 30 <EasingDoubleKeyFrame KeyTime="00:00:00" Value="0"/> 31 <EasingDoubleKeyFrame KeyTime="00:00:02" Value="0"/> 32 <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="1"/> 33 </DoubleAnimationUsingKeyFrames> 34 <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Object" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"> 35 <EasingDoubleKeyFrame KeyTime="00:00:02" Value="1.5"/> 36 <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="1"> 37 <EasingDoubleKeyFrame.EasingFunction> 38 <BackEase EasingMode="EaseIn"/> 39 </EasingDoubleKeyFrame.EasingFunction> 40 </EasingDoubleKeyFrame> 41 </DoubleAnimationUsingKeyFrames> 42 <DoubleAnimationUsingKeyFrames Storyboard.TargetName="Object" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"> 43 <EasingDoubleKeyFrame KeyTime="00:00:02" Value="1.5"/> 44 <EasingDoubleKeyFrame KeyTime="00:00:02.5" Value="1"> 45 <EasingDoubleKeyFrame.EasingFunction> 46 <BackEase EasingMode="EaseIn"/> 47 </EasingDoubleKeyFrame.EasingFunction> 48 </EasingDoubleKeyFrame> 49 </DoubleAnimationUsingKeyFrames> 50 <!-- 効果音・会話 --> 51 <MediaTimeline Source="se.mp3" Storyboard.TargetName="media" BeginTime="00:00:02"/> 52 </Storyboard> 53 54</ResourceDictionary>

補足情報(FW/ツールのバージョンなど)

Visual Studio 2022
C#10.0
WPF

###追記
コメントで教えていただいた、クローンを使う方法を試しました。
結果、以下の例外が発生しました。

System.InvalidOperationException:
'名前 'Object' を解決するために適用できる名前スコープがありません。'

Storyboard中で、Imageコントロール"Object"を操作しており、Cloneしたインスタンスからコントロールのプロパティを変更しようとするのがまずいのかと考えておりますが、はっきりとはしておらず調査中です。

MainWindow.xaml.cs

1namespace Sample 2{ 3 /// <summary> 4 /// Interaction logic for MainWindow.xaml 5 /// </summary> 6 public partial class MainWindow : Window 7 { 8 public MainWindow() 9 { 10 InitializeComponent(); 11 <!-- 変更箇所 --> 12 var sb = (FindResource("SampleStoryboard") as Storyboard).Clone(); 13 <!-- 変更ここまで --> 14 sb.Completed += SampleSb_Completed; 15 sb.Begin(); 16 } 17 18 private void SampleSb_Completed(object? sender, EventArgs e) 19 { 20 <!-- イベント発生時の処理 --> 21 } 22 } 23}
TN8001👍を押しています

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TN8001

2023/01/30 10:08

ResourceDictionaryのStoryboardでTargetNameがあるということですか? Cloneする前はStoryboard自体は動いていたということですか? > Storyboard中で、Imageコントロール"Object"を操作 <Image x:Name="Object" /> に依存するStoryboardをResourceDictionaryに切り出す意味はなんでしょう?(Resourcesの肥大化回避?) なんとなくXY問題な気もします。 [XY問題 - Google 検索](https://www.google.co.jp/search?q=XY%E5%95%8F%E9%A1%8C) スタイルとかテンプレートのレベルでResourceDictionary化できないでしょうかね?
hqf00342

2023/01/30 10:44

Storyboardを以下のコードで試したところ `Completed`イベントは発生しましたが(.NET7, .NET Framework4.8とも) 記載されていないストーリーボード内のアニメーションは終了するようなコードなのでしょうか? `RepeatBehavior="Forever"`のように終了しないアニメーションだと`Completed`イベントは発生しないのではないかと思います。 ```xml <Storyboard x:Key="SampleStoryboard"> <DoubleAnimation Storyboard.TargetName="Object" Storyboard.TargetProperty="Width" From="100" To="200" Duration="0:0:3"/> </Storyboard> ```
TN8001

2023/01/30 12:12

手元でもざっと確認しました。 >> ResourceDictionaryのStoryboardでTargetNameがあるということですか? >> Cloneする前はStoryboard自体は動いていたということですか? MergedDictionariesだと名前が引けないのかと思いましたが、普通に動くしCompletedも来ますね。 > 結果、以下の例外が発生しました。 確かにClone後はInvalidOperationExceptionでした。 Storyboard.SetTarget(sb, Object); を入れれば動きました(が、Clone意味ないですね^^; > Storyboardを以下のコードで試したところ `Completed`イベントは発生しました こちらでも確認できました。 結局当該StoryboardでForeverにしていたということですか?(ResourceDictionaryは何の関係もなく、Foreverでなければ元のコードのままでCompletedが来たということ) > 記載されていないストーリーボード内のアニメーションは終了するようなコードなのでしょうか? どういう意味ですか?? > `RepeatBehavior="Forever"`のように終了しないアニメーションだと`Completed`イベントは発生しないのではないかと思います。 そりゃそうでしょうねぇ。厳密に確認したわけではないですが...(接続を切ったりしたときの動作等) となると本質問は「ForeverのままCompletedが来てほしい」ということになるのですか?(だとしたら私は撤退させていただきます^^;
Hottopia

2023/01/30 23:57 編集

@TN8001さん >ResourceDictionaryのStoryboardでTargetNameがあるということですか? >Cloneする前はStoryboard自体は動いていたということですか? そのとおりです。 ><Image x:Name="Object" /> に依存するStoryboardをResourceDictionaryに切り出す意味はなんでしょう?(Resourcesの肥大化回避?) これに関してもその通りで、Window.Resourceの行数が多くなるのを嫌がってDictionaryに移しました。 Dictionaryの使い方としては間違っていたかもしれません。
Hottopia

2023/01/30 23:57 編集

@hqf00342さん >記載されていないストーリーボード内のアニメーションは終了するようなコードなのでしょうか? >`RepeatBehavior="Forever"`のように終了しないアニメーションだと`Completed`イベントは発生し>ないのではないかと思います。 RepeatBehavior = Forever には設定しておりません。 サンプルコードのご提示ありがとうございます。検証してみます。 一応、Storyboardの詳細なコードを追記します。
Hottopia

2023/01/31 00:02

@TN8001さん ><Image x:Name="Object" /> に依存するStoryboardをResourceDictionaryに切り出す意味はなんでしょう?(Resourcesの肥大化回避?) 今回のように特定のものに依存するStoryboardを作成したい場合、Dictionaryにまとめるのは良い方法ではなさそうなのはなんとなくわかりました。 しかしWindow.Resource部分に記述するのも見通しが悪くなるため、あまりやりたくはありません。 なにか適している方法等はありますか?( #region 等で折りたたむとかでしょうか…)
TN8001

2023/01/31 04:45

hqf00342さんのコメントをHottopiaさんだと勘違いしていました。すいません。 > これに関してもその通りで、Window.Resourceの行数が多くなるのを嫌がってDictionaryに移しました。 「もとはWindow.Resourcesにあったもの(当然予定通り動いていた)を、コード整理のためResourceDictionaryに切り出したらエラーはなくStoryboardも動くのに(C#で追加したはずの)Comletedが来なくなった」ってことですよね? > 一応、Storyboardの詳細なコードを追記します。 「Comletedだけが来ない」というのが再現できません。 Window.Resourcesに直接書いたStoryboardが動いてComleted(xamlで書いてもC#で追加しても)が来るなら、 ResourceDictionaryに書いたStoryboardも動いてComleted(C#で追加した)が来ました。 「Page_Loaded」ということは、本来はPageにあるんでしょうか? なんとなく「実はエラーが出てる(からComletedまでいかない)けど、誰かがそのエラーを飲み込んじゃってる」みたいな状況なんじゃ?って気がします。 テスト用にできるだけシンプルなStoryboardに削っていくと犯人がわかるかもしれません。 > Dictionaryの使い方としては間違っていたかもしれません。 間違っているかどうかはわかりませんが、あまり見ない使い方ではあるとは思います。 MergedDictionariesは「そこに展開する」動作のようですから、提示のようなStoryboardならありな気はします。
hqf00342

2023/01/31 08:44 編集

> Hottopia さん Storyboard見ました。 Storyboard内最後にある<MediaTimeline>を使ってCompletedイベントを取得したことがないのですがこの<MediaTimeline>をコメントアウトするとどうでしょうか?
Hottopia

2023/01/31 07:32

@TN8001さん >Window.Resourcesに直接書いたStoryboardが動いてComleted(xamlで書いてもC#で追加しても)が来るなら、ResourceDictionaryに書いたStoryboardも動いてComleted(C#で追加した)が来ました。 もともと最初からDictionaryに記述しており、Storyboardも正常に動作していました。 hqf00342さんがコメントされた、<MediaTimeline...>をコメントアウトしたところ、 Completedイベントが発生しました。 質問のソースコードに漏れがありました。 MainWindow.xaml中にMediaElementが配置されていて、StoryboardでSourceをセットした後、再生する部分が抜け落ちておりましたため、質問のソースコードを修正しました。
Hottopia

2023/01/31 07:35

@hqf00342さん >Storyboard内最後にある<MediaTimeline>を使ってCompletedイベントを取得したことがないのですがこの<MediaTimeline>をコメントアウトするとどうでしょうか? MediaTimelineをコメントアウトしたところ、Completedイベントが発生しました。 MainWindow.xaml中にMediaElementが配置しているのですが、質問のソースコードでは抜けてましたため、修正しました。
Hottopia

2023/01/31 08:13

StoryboardのMediaTimelineをコメントアウトしたところ、Completedイベントが発生しました。 しかしMediaTimelineの部分もできれば組み込みたく、現在検証中です。
hqf00342

2023/01/31 08:59 編集

すみません、私もお名前間違えていました。 ちょっとテストしてみたら以下の2つの方法でうまくいくようにも見えました。 ・<MediaTimeline Duration="00:00:01">としてDurationでmp3再生を短めに終わらせる ・mp3再生より長いアニメーションを組み込む。例えば以下をStoryboardに追加  <DoubleAnimation Storyboard.TargetName="Object" Storyboard.TargetProperty="(Canvas.Left)" By="0" Duration="0:0:10" /> 不思議ですね。 MediaElement周りは私も知見がないのでテストして頑張ってみてください。
TN8001

2023/01/31 10:23

@Hottopiaさん > StoryboardのMediaTimelineをコメントアウトしたところ、Completedイベントが発生しました。 @hqf00342さん > ちょっとテストしてみたら以下の2つの方法でうまくいくようにも見えました。 「音がほかのアニメより長かった」ということなんですね。難しいw SlipBehavior="Slip"にすると、Completedが来るようになりました。 [ParallelTimeline.SlipBehavior プロパティ (System.Windows.Media.Animation) | Microsoft Learn](https://learn.microsoft.com/ja-jp/dotnet/api/system.windows.media.animation.paralleltimeline.slipbehavior) 音とアニメがあっていたほうがよさそうですが、ラグがあるようにも見えてしまいそうですし調整は必要かもしれません。
hqf00342

2023/01/31 12:20

@TN8001さん メディア再生とアニメの同期の問題ならおっしゃる通り SlipBehavior を使うのが正解ですね。 WPF久しぶりで懐かしかったのとメディア再生込みのアニメーションは作ってこなかったので私も勉強になりました。
Hottopia

2023/02/01 00:36 編集

@TN8001さん @hqf00342さん StoryboardのDurationをメディアの再生時間より長く設定したら、Completedイベントが発生し、やりたい動きになりました。こんな苦戦するとは思いませんでした。ありがとうございました。
hqf00342

2023/02/01 00:17 編集

@Hottopiaさん うまくいったようでよかったです。MS公式的にはSlipBehaviorつけるのが正解のようです。 質問を閉じるために一応回答を書いておきます。
Hottopia

2023/02/01 04:52 編集

@TN8001さん @hqf00342さん お二人とも本当にありがとうございました。 メディア周りを疑うきっかけとなったコメントを下さったこともあり、hqf00342さんの回答をベストアンサーとさせていただきたいと思います。
guest

回答1

0

ベストアンサー

質問で議論されたように、Completedイベントが飛ばないのは今回はStoryboard内のアニメーションとmp3再生の同期が問題のようです。

ですので 手動でアニメーションの長さとmp3再生時間を調整するか、SlipBehavior="Slip" を使うとWPF内で調整されて Completed イベントが発生すると思います。

xml

1<Storyboard x:Key="SampleStoryboard" SlipBehavior="Slip">

MS公式ドキュメントは 質問内の@TN8001さんのコメントを確認してください。

投稿2023/02/01 00:15

hqf00342

総合スコア273

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問