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遇到异步的时候,该怎么办?