Silverlight には、コモンモーダルダイアログボックスが3つほど用意されています。
- ファイルを開くダイアログ ボックス(OpenFileDialog)
- ファイルの保存ダイアログボックス(SaveFileDialog)
- 印刷ダイアログボックス(PrintDocument)
これらのダイアログのうち、SaveFileDialogをIE8で開くとStoryboadが止まってしまう現象が起きます。どういうことかと言いますと、下の画面のようにStoryboardをRepeatBehaviorをForeverにして、回り続けるオブジェクトがあるとします。
このようなSilverlightアプリをIE8で実行し、SaveFileDialogを開くと四角のオブジェクトの回転が止まります。OpenFileDialogとPrintDocumentを開いたときは回り続けます。ちなみにFireFox3やChromeでは、3つのダイアログのうちどれを開いてもオブジェクトは回転し続けます。よって、ダイアログをコモンモーダルダイアログを開いたときにStoryboardが止まらないのが正常動作と思われます。IE8だけのバグとしたら、ずいぶんとピンポイントなバグですね。ちょっと不思議な現象です。
基本的にはSilverlightで作ったアプリはブラウザごとの互換性に悩まされることはないのですが、ゼロにすることはできないことを再確認させられた現象でした。
検証コード
検証に使ったコードを乗せておきます。
<UserControl x:Class="AnimationSample.MainPage" 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" d:DesignHeight="300" d:DesignWidth="400"> <UserControl.Resources> <Storyboard x:Name="Storyboard1" RepeatBehavior="Forever"> <DoubleAnimation Duration="0:0:2" To="360" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.Rotation)" Storyboard.TargetName="rectangle" d:IsOptimized="True"/> </Storyboard> </UserControl.Resources> <Grid x:Name="LayoutRoot"> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="*"/> </Grid.RowDefinitions> <StackPanel> <Button x:Name="OpenFileDialogButton" Content="OpenFileDialog" Width="145"/> <Button x:Name="SaveFileDialogButton" Content="SaveFileDialog" Width="145"/> <Button x:Name="PrintDocumentButton" Content="PrintDocument" Width="145"/> </StackPanel> <Rectangle x:Name="rectangle" Fill="Red" Grid.Row="1" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="0" Width="100" Height="100" RenderTransformOrigin="0.5,0.5"> <Rectangle.RenderTransform> <CompositeTransform/> </Rectangle.RenderTransform> </Rectangle> </Grid> </UserControl>
public partial class MainPage : UserControl { public MainPage() { InitializeComponent(); this.Loaded += this.MainPage_Loaded; this.OpenFileDialogButton.Click += this.OpenFileDialogButton_Click; this.SaveFileDialogButton.Click += SaveFileDialogButton_Click; this.PrintDocumentButton.Click += this.PrintDocumentButton_Click; // 別スレッドでDispatcher キューを通さないで実行する場合の検証用コード var timer = new Timer(state => { System.Diagnostics.Debug.WriteLine(DateTime.Now); }); timer.Change(0, 1000); // Dispatcher キューを通して実行する場合の検証用コード var dt = new DispatcherTimer(); dt.Interval = TimeSpan.FromSeconds(1); dt.Tick += (s, e) => { // とりあえず、画面に配置したボタンに現在時刻を表示してみる。 this.OpenFileDialogButton.Content = DateTime.Now; }; dt.Start(); } private void MainPage_Loaded(object sender, RoutedEventArgs e) { this.Storyboard1.Begin(); } private void OpenFileDialogButton_Click(object sender, RoutedEventArgs e) { // ファイルを開くダイアログ ボックスを表示する。 var dialog = new OpenFileDialog(); if (dialog.ShowDialog() == true) { } } private void SaveFileDialogButton_Click(object sender, RoutedEventArgs e) { // ファイルの保存ダイアログボックスを表示する。 var dialog = new SaveFileDialog(); if (dialog.ShowDialog() == true) { } } private void PrintDocumentButton_Click(object sender, RoutedEventArgs e) { // 印刷ダイアログボックスを表示する。 var pd = new System.Windows.Printing.PrintDocument(); pd.Print("document name"); } }
ちなみに、IE8でSaveFileDialogを開くときもDispatcher キューを通さない場合は、そのスレッドは動作しているようでした。もしかしたら、UIスレッドのみブロックくしてしまうのかもしれません。