Design Your Life

SyntaxHighlight

2013-05-14

Windows 8 開發: 動態更新圖片閃爍 Image update flicker.


這個問題其實遇到蠻久的但一直沒時間好好解決,一直到前陣子開發WP8版本的時候終於"痛定思痛"的好好把它給搞定,其實一部份也是誤打誤撞XD
先來談談我遇到的問題,因為任務的關係,我需要動態更新畫面上的Image,直覺的處理方式如下:

[方法A] Url更新 → 更新Image的來源

String ImageUrl = "http://168.63.133.149/drupal-7/?q=solomon/ws/graph/stockmap/TIMER/" + "?&g=" + Guid.NewGuid();
timerImage.Source = new BitmapImage(new Uri(ImageUrl));
但是可怕的事情發生了,圖片竟然會一閃一閃的,花特?

發生了什麼事情? 就過去的開發經驗是Image在繪圖過程中需要時間,所以需要用技巧雙重緩衝來幫助讓Image畫好才顯示到畫面上。

[方法B] Url更新 → 更新背景Image → 更新Image

String ImageUrl = "http://168.63.133.149/drupal-7/?q=solomon/ws/graph/stockmap/TIMER/" + "?&g=" + Guid.NewGuid();
var BackgroundImage = new BitmapImage(new Uri(ImageUrl));
timerImage.Source = BackgroundImage;
Image照樣給我在那邊閃阿閃的,彷彿在說,打我啊笨蛋XD (背景音樂:一閃一閃亮晶晶)
我不是已經用了雙重緩衝了嗎???
後來查了資料後(但我忘記把網址留下來),資料上說.NET會自動優化Image最後真的要呈現的時候才會把圖片載入到記憶體裡面去,意思就是說,我沒有辦法預載圖片來解決目前畫面圖片閃爍的問題。

經此挫敗只好上論壇拜神,請求各界神人的指導,其中給予指引,不是有DownloadCompleted可以用嗎? 傻傻的,看看這精美的MSDN,你要的一切都在這阿。

但....為什麼我的.NET沒有這個event可以用? 喔~原來是被拿掉了阿!? 只剩下一個Bitmap.ImageOpended可以用...但它同樣也是要圖片載入到記憶體之中才會觸發...

等等,我好像有想法了!

[方法C]如果我用一個看不見的圖片當作緩衝,再把它畫到另一張圖片上呢?

String ImageUrl = "http://168.63.133.149/drupal-7/?q=solomon/ws/graph/stockmap/TIMER/" + "?&g=" + Guid.NewGuid();
Image NotVisibleImage = new BitmapImage(new Uri(ImageUrl));
timerImage.Source = NotVisibleImage.Source;

圖片他還是會閃.........此時我已經快氣絕身亡了

最後的最後,我用了一個Image,並且綁定ImageOpended事件,再把它用Brush的方式畫到Grid上(當作Grid的背景圖片呈現),才解決了直這個問題XD

最後獻上Source Code與論壇文
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<Grid.Resources>
<converters:UrlToImageConverter x:Key="UrlToImageConverter"/>
</Grid.Resources>
<!-- Buffer image -->
<Image Source="{Binding ImageUrl,Mode=TwoWay,Converter={StaticResource UrlToImageConverter}}"
Visibility="Collapsed"
ImageOpened="BufferImage_OnImageOpened"></Image>
<!-- Image grid-->
<Grid Background="{Binding StockImageBrush,Mode=TwoWay}" ></Grid>
<Button Grid.Row="1" Click="ButtonBase_OnClick">Refresh Image</Button>
</Grid>
public partial class MainPage : PhoneApplicationPage
{
//Binding Object
private readonly TimeClock _timeClock = new TimeClock();
// Constructor
public MainPage()
{
InitializeComponent();
DataContext = _timeClock;
}
private void ButtonBase_OnClick(object sender, RoutedEventArgs e)
{
//Trigger imageUrl Update
_timeClock.UpdateImage();
}
private void BufferImage_OnImageOpened(object sender, RoutedEventArgs e)
{
var bufferImage = sender as Image;
var parentGrid = bufferImage.Parent as Grid;
//get image grid by check type of Grid.
var imageGrid = parentGrid.Children.First(child => child.GetType() == typeof (Grid)) as Grid;
//set image background brush
imageGrid.Background = new ImageBrush {ImageSource = bufferImage.Source};
string ImageUrl = "";
var image = new Image {Source = new BitmapImage(new Uri(ImageUrl))};
}
}
internal class TimeClock : BindableBase
{
private static string BaseImageUrl = "http://168.63.133.149/drupal-7/?q=solomon/ws/graph/stockmap/TIMER/";
private static string NewImageUrl
{
get { return BaseImageUrl + "?&g=" + Guid.NewGuid(); }
}
public string _imageUrl = NewImageUrl;
public string ImageUrl
{
get
{
_imageUrl = NewImageUrl;
return _imageUrl;
}
set { SetProperty(ref _imageUrl, value); }
}
public async Task UpdateImage()
{
OnPropertyChanged("ImageUrl");
}
}

沒有留言:

張貼留言