回答済み Gif画像をListBox.ItemTemplateに追加する場合

  • 2012年2月2日 14:39
     
      コードあり

    いつもお世話になっております、Samrilと申します。

    前回、ImageToolを使い、非同期通信で取得したGifファイルURLからGifファイルデータを読み込み、Bitmapに変換する方法を教わりました。

     

    今回は、そのデータをListBoxに表示する方法を探しております。

    WebClientから取得したデータをListで表示するとき、そのデータにある画像URLがGifの場合、どのようにすればいいのでしょうか?

     

    ※ pngやjpgの場合は、Bindingした際に自動的に取得してくれますが、Windows PhoneはGifに対応していないため

     

    XAMLの一部抜粋

    <ListBox Name="ItemListBox">
    
    <ListBox.ItemTemplate>
    
        <DataTemplate>
    
            <StackPanel Orientation="Vertical" Width="Auto" Height="Auto">
    
                <Image Source="{Binding GifImage}" Height="100" Width="100"/>
    
        	    <TextBlock Text="{Binding GifText}" VerticalAlignment="Top"/>
    
            </StackPanel>
    
        </DataTemplate>
    
    </ListBox.ItemTemplate>
    
    </ListBox>
    
    


    CSの一部抜粋

    // コンストラクター
    
    public MainPage()
    
    {
    
        InitializeComponent();
    
         // なんでもいいので、いったんWebClientで非同期をおこなう
    
        WebClient client = new WebClient();
    
        client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
    
        client.DownloadStringAsync(new Uri("http://**********.xml", UriKind.Absolute));
    
    }
    
    
    
    void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    
    {
    
        ///////////////////////////////////////////////////////
    
        // WebClientの結果が次のようにGif画像のURLとテキストだった場合
    
        //   <GifImage>http://***********.gif
    
        //   <GifText>これはGifファイルです
    
        // 
    
        // どのようにしてItemListBox.ItemsSourceにデータを格納できるのか?
    
        ///////////////////////////////////////////////////////
    
        // WebClientの結果をバインド用のクラスに変換する
    
        List<ItemList> itemList = ........;
    
    
    
        // XAMLのListBox.ItemTemplateにデータを格納する
    
        ItemListBox.ItemsSource = itemList;
    
    }
    
    
    // Bind用クラス
    public class ItemList
    
    {
    
        public string GifImage{get;set;}
    
        public string GifText{get;set;}
    
    }
    
    


     

    分かりづらい文章で申し訳ありませんが、ご教授をお願いいたします。

    また、意味がわからないなどがありましたら、お気軽にご返信ください。

すべての返信

  • 2012年2月3日 16:20
     
      コードあり

    苦肉の策ですが、試したソースを紹介します。

    ほんとはもっとスマートな方法があるんじゃないの?と思ってますが、とりあえず他の方が回答されるまでのつなぎとして

     

    Samrilさんのソースをベースに、Twitterのフォロワーから名前とimageを表示するようなコードを書いてみました

    以下のコードでは2種類の方法を試しています。xamlのコメントアウトを変更して処理を切り替えることができます

    (1) _GifImage をバインドするxamlコードを有効にすると bind時にbitmapを返す処理をします。(ただし、このままだとGIFだけしか読めません)

    (2) GifImage をバインドするxamlコードを有効にすると、通常のイメージのロードに失敗した= UrlがGIFを指しているを想定して、ImageFailedイベント内でGIFファイルをロードし直す処理をします。(ほとんどのUrlがjpegで、たまにgifが混ざっているような場合を想定)

     

    Mainpage.xaml

     

    <phone:PhoneApplicationPage 
        x:Class="PhoneAppGifTest.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        FontSize="{StaticResource PhoneFontSizeNormal}"
        Foreground="{StaticResource PhoneForegroundBrush}"
        SupportedOrientations="Portrait" Orientation="Portrait"
        shell:SystemTray.IsVisible="True">
    
        <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
        <Grid x:Name="LayoutRoot" Background="SteelBlue">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
    
            <!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
            <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
                <TextBlock x:Name="ApplicationTitle" Text="マイ アプリケーション" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="ページ名" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
            <!--ContentPanel - 追加コンテンツをここに入力します-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    
                <ListBox Name="ItemListBox">
    
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Vertical" Width="Auto" Height="Auto">
                                <!-- BitmapImageを返す方法 -->
                                <Image Source="{Binding _GifImage}" Height="100" Width="100" />
                                <!-- Image_ImageFailedで処理する方法 -->
                                <!--<Image Source="{Binding _GifImage}" Height="100" Width="100" ImageFailed="Image_ImageFailed" />-->
                                <TextBlock Text="{Binding GifText}" VerticalAlignment="Top"/>
                            </StackPanel>
    
                        </DataTemplate>
    
                    </ListBox.ItemTemplate>
    
                </ListBox>
            </Grid>
        </Grid>
     
        <!--ApplicationBar の使用法を示すサンプル コード-->
        <!--<phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
                <shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                    <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
                </shell:ApplicationBar.MenuItems>
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>-->
    
    </phone:PhoneApplicationPage>
    

     


    Mainpage.xaml.cs

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Microsoft.Phone.Controls;
    using System.Xml.Linq;
    using ImageTools.IO.Gif;
    using ImageTools;
    
    namespace PhoneAppGifTest
    {
        public partial class MainPage : PhoneApplicationPage
        {
            // コンストラクター
            public MainPage()
            {
                InitializeComponent();
                ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
                WebClient client = new WebClient();
    
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
    
                client.DownloadStringAsync(new Uri("https://api.twitter.com/1/statuses/friends.xml?screen_name=konoxl", UriKind.Absolute));
            }
    
            void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
            {
                List<ItemList> itemList = new List<ItemList>();
    
                WebClient client = sender as WebClient;
                XDocument doc =  XDocument.Parse(e.Result);
                foreach (var n in doc.Elements().Descendants("user").Select(p => new { name = p.Element("name").Value, image = p.Element("profile_image_url").Value }))
                {
                    itemList.Add(new ItemList() { GifText = n.name, GifImage = n.image });
                }
                ItemListBox.ItemsSource = itemList;
            }
    
            private void Image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
            {
                //AG_E_NETWORK_ERROR AG_E_UNKNOWN_ERROR
                if (e.ErrorException.Message != "AG_E_UNKNOWN_ERROR")
                    return;
    
                Image obj = sender as Image;
                if (obj != null && obj.Source is System.Windows.Media.Imaging.BitmapImage)
                {
                    ExtendedImage image = new ExtendedImage();
                    image.LoadingCompleted += (s, ex) =>
                    {
                        this.Dispatcher.BeginInvoke(() =>
                        {
                            obj.Source = image.ToBitmap();
                        });
                    };
                    image.UriSource = ((System.Windows.Media.Imaging.BitmapImage)obj.Source).UriSource;
                }
            }
        }
    }
    

     

    バインドしたImageのロードに失敗したときに Image_ImageFailed イベントが起きますが、AG_E_NETWORK_ERROR と AG_E_UNKNOWN_ERROR の2回飛んできます。

    良くわからないけど取り合えずAG_E_UNKNOWN_ERRORの時だけ ImageToolsの力を借りてGIF画像をロードします。

    (本当なら、例外処理とか入れないといけないと思う)

     

    ItemList.cs

     

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using System.Windows.Media.Imaging;
    using ImageTools;
    using System.ComponentModel;
    
    namespace PhoneAppGifTest
    {
        public class ItemList
        {
    
            public BitmapImage _GifImage
            {
                get
                {
                    BitmapImage bmp = new BitmapImage();
                    ExtendedImage image = new ExtendedImage();
                    image.LoadingCompleted += (s,args) => {
                        bmp.Dispatcher.BeginInvoke(() =>
                        {
                            if (bmp.PixelHeight == 0)
                            {
                                bmp.SetSource(image.ToStream());
                                //System.Diagnostics.Debug.WriteLine(bmp.UriSource);
                            }
                        });
                    };
                    image.UriSource = new Uri(this.GifImage, UriKind.RelativeOrAbsolute);
                    return bmp;
    
                }
            }
    
            public string GifImage { get; set; }
    
            public string GifText { get; set; }
        }
    }
    
    


    _GifImageプロパティのGet処理でとりあえず BitmapImageを返して置いて、LoadingCompletedイベント時に bmp.SetSource(image.ToStream()); してます。

     

     

     

     

     

     

     

  • 2012年2月3日 18:52
     
     回答済み コードあり

    こんばんは、CH3COOH(酢酸)です。

    konox1さんのようにシンプルに書けず、回答に時間が掛かってしまいました。申し訳ございません。
    デフォルトでgifファイルのデコーダーがないとこんなに大変だとは……

    ダウンロードしたGIFファイルをキャッシュ画像として分離ストレージに保存して、
    コンバーターを使って、バインディングしたファイルパスからBitmapImageオブジェクトへ変換し、
    ListBoxコントロール上でGIFファイルを表示するようにしてみました。

    利用側からはコレクションにURLを入れておくだけで、
    ダウンロードとキャッシュと表示をしてくれるので、そこそこコードを流用して頂けるのではないかと思います。

     

    MainPage.xamlです。

    <phone:PhoneApplicationPage 
        x:Class="GifTest.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:GifTest"
        mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        FontSize="{StaticResource PhoneFontSizeNormal}"
        Foreground="{StaticResource PhoneForegroundBrush}"
        SupportedOrientations="Portrait" Orientation="Portrait"
        shell:SystemTray.IsVisible="True" Language="ja-JP">
    
        <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
        <Grid x:Name="LayoutRoot" Background="Transparent">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
    
            <!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
            <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
                <TextBlock x:Name="ApplicationTitle" Text="SOFTBUILD" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="gif test" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
            <!--ContentPanel - 追加コンテンツをここに入力します-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
                <ListBox Name="listBox1">
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Vertical" Width="Auto" Height="Auto">
                                <Image Height="200" Width="200" Stretch="UniformToFill">
                                    <Image.Source>
                                        <Binding Path="CachePath" Mode="TwoWay">
                                            <Binding.Converter>
                                                <local:StringToImagerConverter/>
                                            </Binding.Converter>
                                        </Binding>
                                    </Image.Source>
                                </Image>
                                <TextBlock Text="{Binding Text}" VerticalAlignment="Top"/>
                            </StackPanel>
                        </DataTemplate>
                    </ListBox.ItemTemplate>
                </ListBox>
            </Grid>
        </Grid>
     
        <!--ApplicationBar の使用法を示すサンプル コード-->
        <!--<phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
                <shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                    <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
                </shell:ApplicationBar.MenuItems>
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>-->
    
    </phone:PhoneApplicationPage>
    

     


    次にバインディング用のクラス

    ListBoxにバインディングするクラスを定義します。コンストラクタに設定されたURLの画像ファイルをダウンロードしてキャッシュします。

     

    using System.ComponentModel;
    using System.IO.IsolatedStorage;
    using System.Net;
    using Microsoft.Phone.Reactive;
    
    namespace GifTest {
    
        public class ImageInfo : INotifyPropertyChanged {
            public ImageInfo(string url, string text) {
                ImageURL = url;
                Text = text;
    
                var fileName = System.IO.Path.GetFileName(url);
                using (var store = IsolatedStorageFile.GetUserStoreForApplication()) {
                    // 既に画像ファイルがある場合はダウンロードしにいかない
                    if (store.FileExists(fileName)) {
                        CachePath = fileName;
                        return;
                    }
                }
    
                // urlが入ったら画像をダウンロードして、分離ストレージに保存する
                HttpWebRequest req = HttpWebRequest.CreateHttp(url);
                Observable.FromAsyncPattern<WebResponse>(req.BeginGetResponse, req.EndGetResponse)()
                    .Select(res => res.GetResponseStream())
                    .Select(strm => {
                        var cacheFileName = System.IO.Path.GetFileName(url);
                        using (var store = IsolatedStorageFile.GetUserStoreForApplication())
                        using (var strmWriter = store.CreateFile(cacheFileName)) {
                            var bytes = new byte[128];
                            int readed = 0;
                            while (true) {
                                readed = strm.Read(bytes, 0, bytes.Length);
                                if (readed == 0) break;
                                strmWriter.Write(bytes, 0, readed);
                            }
                        }
                        strm.Close();
                        return cacheFileName;
                    })
                    .ObserveOnDispatcher()
                    .Subscribe(cacheFileName => CachePath = cacheFileName);
            }
    
            public string ImageURL { get; set; }
            public string Text { get; set; }
    
            private string _cachePath;
            public string CachePath {
                get { return _cachePath; }
                set {
                    _cachePath = value;
                    OnPropertyChanged("CachePath");
                }
            }
    
            public event PropertyChangedEventHandler PropertyChanged;
            private void OnPropertyChanged(string name) {
                if (PropertyChanged != null) {
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
                }
            }
        }
    }
    

     


    ListBoxにバインドしたキャッシュのファイルパスからBitmapImageオブジェクトへ変換するコンバーターを用意します。ファイルパスの拡張子部分がgifだった場合はImage Toolsを使用して、それ以外の場合はそのままストリームをBitmapImageに設定するようにしました。

    using System;
    using System.Globalization;
    using System.IO;
    using System.IO.IsolatedStorage;
    using System.Windows.Data;
    using System.Windows.Media.Imaging;
    using ImageTools;
    using ImageTools.IO.Gif;
    
    namespace GifTest {
    
        public class StringToImagerConverter : IValueConverter {
    
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
                var filePath = value as string;
                if (filePath == null) {
                    return null;
                }
    
                var bmp = new BitmapImage();
    
                using (var store = IsolatedStorageFile.GetUserStoreForApplication())
                using (var strm = store.OpenFile(filePath, FileMode.Open)) {
    
                    var ext = System.IO.Path.GetExtension(filePath);
                    if (ext.ToLower() == ".gif") {
                        // 拡張子がgifの場合はImageToolsを使用する
                        ExtendedImage image = new ExtendedImage();
                        var decoder = new GifDecoder();
                        decoder.Decode(image, strm);
                        bmp.SetSource(image.ToStream());
                    } else {
                        // 拡張子がgif以外の場合はImageToolsを
                        // そのままBitmapImageにストリームを食わせる
                        bmp.SetSource(strm);
                    }
                }
    
                return bmp;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) {
                throw new NotImplementedException();
            }
        }
    }
    


    あとは、ListBoxにバインドする元ネタのコレクションを作成して、ItemSourceに設定して終わりです。

    using System;
    using System.Collections.ObjectModel;
    using System.IO;
    using System;
    using System.Collections.ObjectModel;
    using System.IO;
    using System.IO.IsolatedStorage;
    using System.Windows;
    using System.Windows.Navigation;
    using ImageTools.IO;
    using ImageTools.IO.Gif;
    using Microsoft.Phone.Controls;
    
    namespace GifTest {
        public partial class MainPage : PhoneApplicationPage {
            // コンストラクター
            public MainPage() {
                InitializeComponent();
    
                // デコーダーを追加する
                Decoders.AddDecoder<GifDecoder>();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e) {
    
                var list = new ObservableCollection<ImageInfo>();
                list.Add(new ImageInfo("https://p.twimg.com/AkKIvbKCQAACN04.jpg", "てすと1"));
                list.Add(new ImageInfo("https://p.twimg.com/Acg5qLwCMAEiBW-.jpg", "てすと2"));
                list.Add(new ImageInfo("http://ch3cooh.jp/files/sample_gif/image01.gif", "てすと3"));
                list.Add(new ImageInfo("http://ch3cooh.jp/files/sample_gif/image02.gif", "てすと4"));
                list.Add(new ImageInfo("http://ch3cooh.jp/files/sample_gif/image03.gif", "てすと5"));
                list.Add(new ImageInfo("http://ch3cooh.jp/files/sample_gif/image04.gif", "てすと6"));
                list.Add(new ImageInfo("http://ch3cooh.jp/files/sample_gif/image05.gif", "てすと7"));
                list.Add(new ImageInfo("http://ch3cooh.jp/files/sample_gif/image06.gif", "てすと8"));
                list.Add(new ImageInfo("http://ch3cooh.jp/files/sample_gif/image07.gif", "てすと9"));
                listBox1.ItemsSource = list;
            }
        }
    }
    


     

    • 回答としてマーク Samril 2012年2月5日 9:19
    •  
  • 2012年2月4日 1:04
     
     回答済み コードあり

    酢酸さんの回答を見て IValueConverterを使うように書き換えてみました

     

    MainPage.xaml

    <phone:PhoneApplicationPage 
        x:Class="PhoneAppGifTest.MainPage"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
        xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768"
        FontFamily="{StaticResource PhoneFontFamilyNormal}"
        FontSize="{StaticResource PhoneFontSizeNormal}"
        Foreground="{StaticResource PhoneForegroundBrush}"
        SupportedOrientations="Portrait" Orientation="Portrait"
        shell:SystemTray.IsVisible="True" xmlns:my="clr-namespace:PhoneAppGifTest">
        <phone:PhoneApplicationPage.Resources>
            <my:StringToImagerConverter x:Key="StringToImagerConverter1" />
        </phone:PhoneApplicationPage.Resources>
        <!--LayoutRoot は、すべてのページ コンテンツが配置されるルート グリッドです-->
        <Grid x:Name="LayoutRoot" Background="SteelBlue">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"/>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
    
            <!--TitlePanel は、アプリケーション名とページ タイトルを格納します-->
            <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
                <TextBlock x:Name="ApplicationTitle" Text="マイ アプリケーション" Style="{StaticResource PhoneTextNormalStyle}"/>
                <TextBlock x:Name="PageTitle" Text="ページ名" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
            </StackPanel>
    
            <!--ContentPanel - 追加コンテンツをここに入力します-->
            <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
    
                <ListBox Name="ItemListBox">
    
                    <ListBox.ItemTemplate>
                        <DataTemplate>
                            <StackPanel Orientation="Vertical" Width="Auto" Height="Auto">
                                <!-- BitmapImageを返す方法 -->
                                <!--<Image Source="{Binding _GifImage}" Height="100" Width="100" />-->
                                <!-- Image_ImageFailedで処理する方法 -->
                                <!--<Image Source="{Binding _GifImage}" Height="100" Width="100" ImageFailed="Image_ImageFailed" />-->
                                <!--コンバータで処理する方法-->
                                <Image Source="{Binding Path=GifImage, Converter={StaticResource StringToImagerConverter1}}" Height="100" Width="100" />
                                <TextBlock Text="{Binding GifText}" VerticalAlignment="Top"/>
                            </StackPanel>
    
                        </DataTemplate>
    
                    </ListBox.ItemTemplate>
    
                </ListBox>
            </Grid>
        </Grid>
     
        <!--ApplicationBar の使用法を示すサンプル コード-->
        <!--<phone:PhoneApplicationPage.ApplicationBar>
            <shell:ApplicationBar IsVisible="True" IsMenuEnabled="True">
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button1.png" Text="Button 1"/>
                <shell:ApplicationBarIconButton IconUri="/Images/appbar_button2.png" Text="Button 2"/>
                <shell:ApplicationBar.MenuItems>
                    <shell:ApplicationBarMenuItem Text="MenuItem 1"/>
                    <shell:ApplicationBarMenuItem Text="MenuItem 2"/>
                </shell:ApplicationBar.MenuItems>
            </shell:ApplicationBar>
        </phone:PhoneApplicationPage.ApplicationBar>-->
    
    </phone:PhoneApplicationPage>
    

     

    Bind にコンバータを追加。

     

     

     

    MainPage.xaml.cs

     

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Microsoft.Phone.Controls;
    using System.Xml.Linq;
    using ImageTools.IO.Gif;
    using ImageTools;
    using System.Windows.Data;
    using System.Windows.Media.Imaging;
    
    namespace PhoneAppGifTest
    {
        public partial class MainPage : PhoneApplicationPage
        {
            // コンストラクター
            public MainPage()
            {
                InitializeComponent();
                ImageTools.IO.Decoders.AddDecoder<GifDecoder>();
                WebClient client = new WebClient();
    
                client.DownloadStringCompleted += new DownloadStringCompletedEventHandler(client_DownloadStringCompleted);
    
                client.DownloadStringAsync(new Uri("https://api.twitter.com/1/statuses/friends.xml?screen_name=konoxl", UriKind.Absolute));
            }
    
            void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
            {
                List<ItemList> itemList = new List<ItemList>();
    
                WebClient client = sender as WebClient;
                XDocument doc =  XDocument.Parse(e.Result);
                foreach (var n in doc.Elements().Descendants("user").Select(p => new { name = p.Element("name").Value, image = p.Element("profile_image_url").Value }))
                {
                    itemList.Add(new ItemList() { GifText = n.name, GifImage = n.image });
                }
                ItemListBox.ItemsSource = itemList;
            }
    
            //private void Image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
            //{
            //    //AG_E_NETWORK_ERROR AG_E_UNKNOWN_ERROR
            //    if (e.ErrorException.Message != "AG_E_UNKNOWN_ERROR")
            //        return;
    
            //    Image obj = sender as Image;
            //    if (obj != null && obj.Source is System.Windows.Media.Imaging.BitmapImage)
            //    {
            //        ExtendedImage image = new ExtendedImage();
            //        image.LoadingCompleted += (s, ex) =>
            //        {
            //            this.Dispatcher.BeginInvoke(() =>
            //            {
            //                obj.Source = image.ToBitmap();
            //            });
            //        };
            //        image.UriSource = ((System.Windows.Media.Imaging.BitmapImage)obj.Source).UriSource;
            //    }
            //}
        }
    
    
        public class StringToImagerConverter : IValueConverter
        {
    
            public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                var filePath = value as string;
                if (filePath == null)
                {
                    return null;
                }
    
                BitmapImage bmp = new BitmapImage();
                if (System.IO.Path.GetExtension(filePath) == ".gif")
                {
                    ExtendedImage image = new ExtendedImage();
                    image.LoadingCompleted += (s, args) =>
                    {
                        bmp.Dispatcher.BeginInvoke(() =>
                        {
                            bmp.SetSource(image.ToStream());
                            System.Diagnostics.Debug.WriteLine("Loaded Gif {0}", filePath);
                        });
                    };
                    image.UriSource = new Uri(filePath, UriKind.RelativeOrAbsolute);
                }
                else
                {
                    bmp.UriSource = new Uri(filePath, UriKind.RelativeOrAbsolute);
                    System.Diagnostics.Debug.WriteLine("Loaded other {0}", filePath);
                }
    
                return bmp;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
            {
                throw new NotImplementedException();
            }
    
        }
    
    }
    

     

    IValueConverter を追加しました。拡張子で処理を変えるようにもしてみました

     

     

    ItemList.cs

     

    using System;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Ink;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    //using System.Windows.Media.Imaging;
    //using ImageTools;
    //using System.ComponentModel;
    
    namespace PhoneAppGifTest
    {
        public class ItemList
        {
    
            //public BitmapImage _GifImage
            //{
            //    get
            //    {
            //        BitmapImage bmp = new BitmapImage();
            //        ExtendedImage image = new ExtendedImage();
            //        image.LoadingCompleted += (s,args) => {
            //            bmp.Dispatcher.BeginInvoke(() =>
            //            {
            //                if (bmp.PixelHeight == 0)
            //                {
            //                    bmp.SetSource(image.ToStream());
            //                    System.Diagnostics.Debug.WriteLine(bmp.UriSource);
            //                }
            //            });
            //        };
            //        image.UriSource = new Uri(this.GifImage, UriKind.RelativeOrAbsolute);
            //        return bmp;
    
            //    }
            //}
    
            public string GifImage { get; set; }
    
            public string GifText { get; set; }
        }
    }
    
    

     

    コンバータで処理するのでデータクラスにimageの処理はいらなくなってすっきりしました

    キャッシュ処理はいれてませんが、これで昨日私が書いたソースよりは多少ましになったと思います

     

     

     



    • 編集済み konox1 2012年2月4日 1:05
    • 編集済み konox1 2012年2月4日 1:07
    • 回答としてマーク Samril 2012年2月5日 9:19
    •