Windows Phone - 非同步下載圖片結合Data Binding
這篇文章主要記錄最近在撰寫一個App所遇到的問題,其問題的說明如下:
a. 資料來源只有給圖片的URL,所以需要非同步下載圖片;
b. 利用URL下載圖片時,需要給予帳號密碼驗證;
c. 利用DataBinding方式更新畫面的資料;
了解上述三個需求後,該怎麼來處理呢?透過以下的步驟來說明:
(1) 建立一個Model用來描述圖片物件的基本資訊;
public class image : INotifyPropertyChanged
{
public string imageId { get; set; }
private string gurl = string.Empty;
public string url
{
get { return gurl; }
set
{
gurl = value;
//進行非同步下載圖像
AysncDownloadImage();
}
}
public string imageDesc { get; set; }
public string imageType { get; set; }
public string isRecommend { get; set; }
public string imageExist { get; set; }
#region 圖片非同步下載+DataBinding功能
private BitmapImage gimgsource = null;
[IgnoreDataMember]
public BitmapImage imgsource
{
get
{
return gimgsource;
}
set
{
if (value != gimgsource)
{
gimgsource = value;
OnPropertyChanged();
}
}
}
#endregion
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string pPropertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(pPropertyName));
}
}
}
定義物件時多增加獨立屬性「imagesource」宣告為BitmapImage的類型,在set該屬性時多呼叫了OnPropertyChange()
用於DataBinding之用。另外,在url屬性被set值時,呼叫非同步下載圖像藉由它來set imagesource屬性通知更新畫面。
(2) 實作Model中非同步下載圖像並更新BitmapImage屬性值;
private AsyncDownloadImage()
{
try
{
WebClient tClient = new WebClient();
tClient.Credentials = new NetworkCredential("pou", "123456@");
tClient.OpenReadCompleted += (obj, e) =>
{
if (e.Error == null && !e.Cancelled)
{
//將下載好的Stream放入BitmapImage,並設定獨立DataBinding的屬性
this.imgsource = new BitmapImage();
this.imgsource.SetSource(e.Result);
}
else
{
//代表載入失敗的圖
Debug.WriteLine(string.Format("Failed,{1}", this.url));
}
};
tClient.OpenReadAsync(new Uri(gurl));
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
}
}
該類別實作INotifyPropertyChanged,讓非同步下載完圖片後,藉由修改BitmapImage屬性即直接通知UI進行更新,
這是MVVM的理念。其中在下載圖片時因為需要予帳號密碼,因而透過NetworkCredential 類別來提供。
(3) XAML定義畫面的Binding;
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<ListBox x:Name="testListBox">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid x:Name="LayoutRoot" Background="{StaticResource PhoneChromeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="70*" />
<ColumnDefinition Width="30*" />
</Grid.ColumnDefinitions>
<!-- 圖片Binding的是非同步下載圖片更新的imagesource(BitmapImage)屬性,就不是url屬性。 -->
<Image Grid.Column="0" Source="{Binding imagesource}"
Height="100" Width="100" Stretch="UniformToFill" />
<TextBlock x:Name="txtContent" Grid.Column="1" Text="{Binding imageId}" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox2>
</Grid>
(4) 執行結果:
======
以上是分享透過WebClient搭配指定NetworkCredential的方式向指定的URL下載圖片,
最後再搭配DataBinding的方式將圖更新於畫面。這樣的作法主要原因在於非同步下載時需要給予帳號、密碼的部分,
如果只是單純透過GET就可以下載的圖片,我就不建議使用這樣的方式,
可以改由直接使用「new Uri("url");」的Uri屬性來DataBinding至畫面上。
希望對大家在處理DataBinding需要圖片時可以有所幫助。
References:
‧Converting Stream to byte array after asynchronously downloading in Windows Phone
‧How to Load an Image from a URL in Windows Phone 8?
‧WebClient.OpenReadAsync 方法 (Uri, Object)
‧Asynchronous Image download on Windows Phone 7
‧How do I download images (jpg) via a webclient and save to isolated storage on Windows Phone 7?
‧Async Implementation of IValueConverter
‧Async Implementation of IValueConverter
‧Silverlight实用示例 - 深入了解Silverlight的IValueConverter和TypeConverter
‧Silverlight IValueConverter for Image Urls