BitmapImage.SetSource(Stream)で画像が表示されないケースがあるバグ?
Microsoft情報で確認してないけど、明らかに Silverlight 2.0 beta 1 のバグと思われるケースに遭遇して丸1日ハマってしまった…。対処法がわかったのでメモとして残しておく事に。
やりたいこと
WebClient.OpenReadAsync() で 画像データの Stream を取得して、画面に表示するだけ。
バグの現象
WebClient.OpenReadAsync() で Stream の取得まではできているのだが、画面に表示する事ができないケースがある。(表示できる時もある)
いろいろ試した結果、以下の条件に該当する時に発生する事がわかった。
バグが発生するコード
文章で書いても判り辛いと思うので、バグが発生するコードを。
Page.xaml
<UserControl x:Class="SilverlightImageBug.Page" xmlns="http://schemas.microsoft.com/client/2007" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Width="400" Height="300"> <StackPanel x:Name="LayoutRoot" Background="White"> <Button Content="表示" Height="24" x:Name="button" Click="button_Click" /> <Image x:Name="image1" /> </StackPanel> </UserControl>
Page.xaml.cs
using System; using System.Windows.Controls; using System.Net; using System.Windows; using System.Windows.Media.Imaging; namespace SilverlightImageBug { public partial class Page : UserControl { public Page() { InitializeComponent(); } private void button_Click(object sender, System.Windows.RoutedEventArgs e) { WebClient webClient = new WebClient(); webClient.OpenReadCompleted += delegate(object _sender, OpenReadCompletedEventArgs _e) { BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(_e.Result); image1.Source = bitmapImage; }; webClient.OpenReadAsync(new Uri("hoge.jpg", UriKind.Relative)); } } }
このプログラムを動かしても、画像が画面に表示されない。
対処法
このバグを回避する方法は2つ。
Image.Visibility = Visibility.Visible; を追加する。
SetSource() の後ろに、Image のインスタンスの Visibility へ Visibility.Visible を設定する1行を追加する。
private void button_Click(object sender, System.Windows.RoutedEventArgs e) { WebClient webClient = new WebClient(); webClient.OpenReadCompleted += delegate(object _sender, OpenReadCompletedEventArgs _e) { BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(_e.Result); image1.Source = bitmapImage; image1.Visibility = Visibility.Visible; // ← この行を追加 }; webClient.OpenReadAsync(new Uri("hoge.jpg", UriKind.Relative)); }
Image のインスタンスを必要な時に生成する
あらかじめ XAML に Image 要素を記述しておくのをやめて、表示が必要になったタイミングで Image のインスタンスを作って、レイアウトに Add() するように修正する。
private void button_Click(object sender, System.Windows.RoutedEventArgs e) { WebClient webClient = new WebClient(); webClient.OpenReadCompleted += delegate(object _sender, OpenReadCompletedEventArgs _e) { BitmapImage bitmapImage = new BitmapImage(); bitmapImage.SetSource(_e.Result); Image image = new Image(); // ← Imageのインスタンス自体を image.Source = bitmapImage; // 動的に生成して、Add() LayoutRoot.Children.Add(image); // }; webClient.OpenReadAsync(new Uri("hoge.jpg", UriKind.Relative)); }
補足
どうやら XAML に Source が指定されていない Image 要素が記述されている場合、初期表示処理が終わった段階で Visibility が Visibility.Collapsed として扱われてしまうようだ。
しかし、その状態でも Visibility の値を確認すると、Visible が返ってくる。(これがバグだと思ってる根拠)