Binding之於MVVM來說的重要性無需多說,Binding之於DataTemplate來說的重要性也無需多說,Binding的重要性也無需多說,異步也不用多說了,今天就到此為止吧。。。
-------------------------------------------------冷冷的分割線------------------------------------------------------
但是,當你要binding的數據是一個需要異步操作的結果的時候呢?
這是我們在項目中遇到的實際問題,一度困擾了我很長時間,這篇文章是我探索的過程,在這個過程中,我嘗試用不同的方案來解決這個問題,並且咨詢了其它朋友,終於找到了一種解決方案,而且更加深入地了解了DataTemplate的工作機制,我覺得很有必要紀錄下來,重新梳理這個探索的過程,應該會對遇到同樣問題的同學有所幫助。
我們的需求:
顯示一組縮略圖的濾鏡效果,用戶點擊了這個濾鏡,可以在頁面上看到應用了這個濾鏡的效果 ,類似於這種效果
我們的解決方案:
1. 需要一個項集合控件,類似於ListBox (UI工作)
2. 需要一個ItemControl,用於顯示濾鏡的名稱和處理過的縮略圖(UI)
3. 需要一個濾鏡類,需要包含濾鏡名和濾鏡信息(數據)
4. UI與數據結合
開始動手--方案一:
1. 先把數據做起來,我們給出了這么一個類,代表我的濾鏡
public class MyFilter { public FilterData Filter{get;set;} // 濾鏡相關信息 public FilterName Name{get;set;} // 濾鏡名 }
2. 項集合控件,MyItemsControl,有一個ItemsSource,接收一個List<MyFilter>的數據源
3. Item控件,用於顯示濾鏡名和展示應用過該濾鏡的縮略圖,MyItemControl,我只需要一個數據源,將MyItemControl的DataContext設置為這個數據源,然后使用binding就OK,由於Image需要的是一個ImageSource的數據源,所以我還需要一個轉換器,將FilterData轉換為WriteableBitmap
<UserControl.Resources>
<local:WriteableBitmapConverter x:name="imageConverter"/>
</UserControl.Resources>
<UserControl> <Grid> <Image x:Name="FilterImage" Binding={MyFilterData, Converter={StaticResource imageConverter} /> <TextBlock x:Name="FilterNameTB" Binding= {MyFilterName}/> </Grid> </UserControl>
4. 最后一步,實現這個WriteableBitmapConverter,將數據轉換為可以被Image接收的WriteableBitmap:
public class ImageConverter : IValueConverter { public async Task<object> Convert(object value, Type targetType, object parameter, string language) { WriteableBitmap thumb = await SDK.GetThumbAsync(); var filterData = value as MyFilterData; WriteableBitmap renderedResult = await SDK.RenderAsync(thumb, filterData); return renderedResult; } public object ConvertBack(object value, Type targetType, object parameter, string language) { throw new NotImplementedException(); } }
OH,NO!為了保證用戶體驗和UI的流暢性,我的SDK被設計成了異步操作,轉換器里面能這么寫么?答案很明顯,不行。
那么問題來了:當Binding遇到異步的時候,該怎么辦?