最近学习MVVM,至于什么是MVVM我也在这儿不多说了,一是关于它的解释解释网上非常多,二是我怕自己讲不清,误导自己没关系,误导别人就不好了。。
好了,废话结束,看是实战......
这个必应壁纸的demo非常简单,只有一个页面,上面有一个Image,一个TextBox和两个Button控件。
如下图所示
那么下面吧XAML代码贴上来
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <Grid> <Grid.RowDefinitions> <RowDefinition /> <RowDefinition Height="auto"/> <RowDefinition Height="auto"/> </Grid.RowDefinitions> <Image Source="{Binding ImageSource}"></Image> <TextBox Grid.Row="1" Text="{Binding Copyright}" IsReadOnly="True"></TextBox> <Grid HorizontalAlignment="Stretch" Grid.Row="2"> <Grid.ColumnDefinitions> <ColumnDefinition/> <ColumnDefinition/> </Grid.ColumnDefinitions> <Button Content="上一张" Command="{Binding ButtonCommand}" CommandParameter="上一张" HorizontalAlignment="Center" Grid.Column="0"></Button> <Button Content="下一张" Command="{Binding ButtonCommand}" CommandParameter="下一张" HorizontalAlignment="Center" Grid.Column="1"></Button> </Grid> </Grid> </Grid>
在设计的时候,我是先设计的ViewModel,但是由于设计ViewModel的时候我已经知道必应壁纸的请求参数。
http://cn.bing.com/HPImageArchive.aspx?format=js&idx=idx=0&n=1
有三个查询参数
format:这个应该是指定返回数据类型,默认设成js不变
idx:如果你想获取昨天的壁纸,那么这个参数就是1,如果是获取前天的壁纸,那么这个就是2,经过我测试,他的取值范围是[-1,15],比较有意思的是,-1应该就是明天的壁纸吧,嘿嘿
n:表示返回数据中包含几组图片信息,我设为1
由于我设置的返回格式是json,json的解析我就不贴了,放在demo中,咋们的重点也不是这个。
为了在下面的ViewModel中不出现混乱,我先给出Model的定义。
namespace 必应壁纸实战.Model { public class BingImageModel {public string copyright { get; set; }//返回图片的copyright public Uri uri { get; set; } //返回具体图片的uri public int idx { get; set; } = 0; public int n { get; set; } = 1; } }
ViewModel的设计是我结合了View中的需求设计的。
namespace 必应壁纸实战.ViewModle { public class BingImageViewModel: ViewModelBase { private string _copyright; public string Copyright { get { return _copyright; } set { _copyright = value; OnPropertyChanged(); } } private BitmapImage _imageSource; public BitmapImage ImageSource { get { return _imageSource; } set { _imageSource = value; OnPropertyChanged(); } } private int index; public int Index { get { return index; } set { if (value <= 0) value = 0; index = value; IndexChanged(); } } public RelayCommand ButtonCommand { get; set; } public BingImageModel Model { get; set; } private void ButtonDown(object param) { string tag = param as string; if (tag != null) { if (tag == "上一张") { Index++; } else { Index--; } } } public BingImageViewModel() { Model = new BingImageModel(); ButtonCommand = new RelayCommand(); ButtonCommand.ExcuteParam = ButtonDown; Index = 0; Copyright = ""; } private async void IndexChanged() { Model = await HttpService.GetBingImageModel(Index); if (Model != null) { ImageSource = await HttpService.GetBingImage(Model); Copyright = Model.copyright; } } } }
我对ViewModel做一个简单说明
ImageSource和Image空间的Source属性绑定
Copyright和TextBox的Text属性绑定
ButtonCommand和两个Button的Command属性绑定,并且通过CommandParameter来区别执行的命令
Index对应请求参数idx,在它的值改变后执行IndexChanged来获取必应壁纸
ButtonDown方法对应ButtonCommand来实现对Index的修改,自增代表前一天,自减代表后一天
Model封装了获取壁纸的一些必要信息,结合Service中定义的HttpClinet的helper来实现具体的网络数据请求。
此外,作为WVVM的必备模式,ViewModel是继承自ViewModelBase的,用以实现绑定机制。
完成View,ViewModel,和Model后,一定不要忘记在View中对ViewModel的绑定,最简单就是类似于“this.DataContext=new ViewModel();”了。
到这儿就基本完成了,但感觉写的有些混乱,我把整个过程中的几个坑在这儿说说
1.就是关于WVVM,一直没有弄明白在ViewModel中写大量的代码究竟好不好,我还有待研究;
2.用Windows.Web.Http命名空间定义的HttpClient请求图片数据后,用如下方式实现对一个BitmapImage对象的设置
BitmapImage bitMap = new BitmapImage(); ; var response=await HttpClient.GetAsync(model.uri); var buffer = await response.Content.ReadAsBufferAsync(); byte[] bytes = new byte[buffer.Length]; buffer.CopyTo(bytes); //CopyTo是一个定义在System.Runtime.InteropServices.WindowsRuntime;的对IBuffer的拓展方法,这个一定注意 using (MemoryStream memoryStream = new MemoryStream(bytes)) { var randomstream = memoryStream.AsRandomAccessStream(); await bitMap.SetSourceAsync(randomstream); }
好了,上demo代码,点击“我是代码”下载