人间风景开发日志 – 2 <DataModel,ViewModel>
2010-02-03 16:26
253 查看
Data Model
数据模型基本上算是一个人间API数据模型的简单封装,使用人间API的XML版本,并使用LINQ to XML读取数据。
Gender这个地方采取了特殊处理,因为User的GUI是用DataModel直接绑定的,所以这里我先偷了个懒,直接放上了界面颜色数据,此处比较好的做法是做一个ValueConverter来处理。这算是一个Todo Item吧。
View Model
View Model层有两个重要的用来和UI绑定的类,一个是RenjianViewModel,另一个是ImageViewModel。
RenjianViewModel是一个General的ViewModel,包含了对其他各个DataModel,ViewModel以及Command的引用,它是用来和整个窗体的DataContext绑定的。
ImageViewModel是图片的ViewModel。因为严格来说,图片并不是一个数据模型,而我又希望能有一个business object来对图片进行统一管理,其中还包含了很多显示上的tricks,所以这边在ViewModel层单独创建了一个ImageViewModel。
另外一个辅助的ViewModel类是SavingStateViewModel,它用来和UI的Save状态绑定。当用户选择保存喜欢的图片到本地时,会显示一个正在save的层,这个层上面的数据就是从这个ViewModel绑定中得到的。
下面分别就两个比较重要的ViewModel类谈一下一些实现上的tricks。
RenjianViewModel
这个类没什么好说的,一堆对其他ViewModel和DataModel的引用而已,只是有一个方法要解释一下:
这个方法是用来更新文件的本地存储状态的。
当你喜欢的图片被保存到本地之后,图片显示会使用本地的图片,从而提高速度,而图片列表中的thumbnail下方也会显示一个indicator来提示用户。这个方法就是来更新这个状态的。
为什么需要这个方法呢,因为在保存整个conversation的图片的时候,要在下面的列表中更新相关图片的状态,但是conversation图片列表的ImageViewModel全部是新建的,跟下面完整列表的ImageViewModel没有关系,所以需要在这里做一个check,保证所有在main list的ImageViewModel的状态都得到更新。为什么不直接在conversation图片列表中引用main list的ImageViewModel呢?因为在conversation图片列表出来的时候,下面的图片有可能还没有加载,与其部分同步,还不如直接分开,长痛不如短痛嘛。
ImageViewModel
这个ViewModel很复杂,甚至超过了我预期的庞大。
因为Windows Vista之后Microsoft采用了WIC来显示图片,WPF也是如此。而这个组件是具有设备无关特性的,说白了就是DPI相关的,也就是平时在Windows XP上看很正常的图片,如果DPI设置不对的话,在WPF的图片组件上显示就是变型失真。所以里面采用了一系列的tricky来fix这个问题。
还有一个问题是WPF至今没有办法处理gif动画,所以在ImageViewModel里面,我又用了一系列的tricky来处理gif动画的渲染。
GIFImageControl这个第三方的类处理了gif的动画问题,不过这里又引入了两个还没有解决的问题。
第一个是因为GIFImageControl这个类并不是标准的WPF Image类,所以它失去了stretch的功能,那就是说,所有gif的图片都不能在RIV上拉伸,而只能以原始大小显示。
第二个是,这个类本来只需要用来处理包含动画的gif,但是目前只采用了文件后缀判断,所以不包含动画的gif也会用这个类来渲染,而某些被强制改了后缀的gif动画却不能得到显示。
好了,DataModel和ViewModel的大致介绍就这么多,下一篇是关于GUI的实现的描述。
本篇对应代码下载:#53865
相关文章:
人间风景(Renjian Image Viewer, RIV)最新版本预览
人间风景开发日志 – 1 <介绍,文件结构>
数据模型基本上算是一个人间API数据模型的简单封装,使用人间API的XML版本,并使用LINQ to XML读取数据。
namespace RenjianImageViewer.DataModel { class UserModel { private long id; public string NickName { get; private set; } public string UserName { get; private set; } public string Gender { get; private set; } public string Avater { get; private set; } public UserModel(string xmlString) : this(XElement.Parse(xmlString)) { } public UserModel(XElement userElement) { id = (long)userElement.Element("id"); NickName = userElement.Element("name").Value; UserName = userElement.Element("screen_name").Value; Avater = userElement.Element("profile_image_url").Value; Gender = userElement.Element("gender").Value == "1" ? "DeepSkyBlue" : "Pink"; } } }
Gender这个地方采取了特殊处理,因为User的GUI是用DataModel直接绑定的,所以这里我先偷了个懒,直接放上了界面颜色数据,此处比较好的做法是做一个ValueConverter来处理。这算是一个Todo Item吧。
View Model
View Model层有两个重要的用来和UI绑定的类,一个是RenjianViewModel,另一个是ImageViewModel。
RenjianViewModel是一个General的ViewModel,包含了对其他各个DataModel,ViewModel以及Command的引用,它是用来和整个窗体的DataContext绑定的。
ImageViewModel是图片的ViewModel。因为严格来说,图片并不是一个数据模型,而我又希望能有一个business object来对图片进行统一管理,其中还包含了很多显示上的tricks,所以这边在ViewModel层单独创建了一个ImageViewModel。
另外一个辅助的ViewModel类是SavingStateViewModel,它用来和UI的Save状态绑定。当用户选择保存喜欢的图片到本地时,会显示一个正在save的层,这个层上面的数据就是从这个ViewModel绑定中得到的。
下面分别就两个比较重要的ViewModel类谈一下一些实现上的tricks。
RenjianViewModel
这个类没什么好说的,一堆对其他ViewModel和DataModel的引用而已,只是有一个方法要解释一下:
public void UpdateImagesIsLocalStatus() { long temp = 0; var conversitionIDs = from imageModel in ConversitionImages select imageModel.StatusID; var idList = conversitionIDs.ToList(); foreach (var image in Images) { if (idList.Contains(image.StatusID)) { image.IsLocal = true; idList.Remove(image.StatusID); if (idList.Count == 0) { break; } } } }
这个方法是用来更新文件的本地存储状态的。
当你喜欢的图片被保存到本地之后,图片显示会使用本地的图片,从而提高速度,而图片列表中的thumbnail下方也会显示一个indicator来提示用户。这个方法就是来更新这个状态的。
为什么需要这个方法呢,因为在保存整个conversation的图片的时候,要在下面的列表中更新相关图片的状态,但是conversation图片列表的ImageViewModel全部是新建的,跟下面完整列表的ImageViewModel没有关系,所以需要在这里做一个check,保证所有在main list的ImageViewModel的状态都得到更新。为什么不直接在conversation图片列表中引用main list的ImageViewModel呢?因为在conversation图片列表出来的时候,下面的图片有可能还没有加载,与其部分同步,还不如直接分开,长痛不如短痛嘛。
ImageViewModel
这个ViewModel很复杂,甚至超过了我预期的庞大。
因为Windows Vista之后Microsoft采用了WIC来显示图片,WPF也是如此。而这个组件是具有设备无关特性的,说白了就是DPI相关的,也就是平时在Windows XP上看很正常的图片,如果DPI设置不对的话,在WPF的图片组件上显示就是变型失真。所以里面采用了一系列的tricky来fix这个问题。
System.Windows.Controls.Image imageControl = new System.Windows.Controls.Image(); BitmapImage image = new BitmapImage(); image.DownloadCompleted += (s, e) => { imageControl.MaxWidth = image.PixelWidth; imageControl.MaxHeight = image.PixelHeight; }; image.BeginInit(); image.UriCachePolicy = new System.Net.Cache.RequestCachePolicy(System.Net.Cache.RequestCacheLevel.CacheIfAvailable); image.CacheOption = BitmapCacheOption.OnDemand; image.CreateOptions = BitmapCreateOptions.IgnoreColorProfile; image.DownloadFailed += new EventHandler<System.Windows.Media.ExceptionEventArgs>(image_DownloadFailed); image.UriSource = new Uri(ImageUrl); image.EndInit(); if (!image.IsDownloading) { imageControl.MaxWidth = image.PixelWidth; imageControl.MaxHeight = image.PixelHeight; } try { imageControl.Stretch = System.Windows.Media.Stretch.Uniform; imageControl.StretchDirection = StretchDirection.Both; imageControl.Source = image; result = imageControl; } catch { return null; }
还有一个问题是WPF至今没有办法处理gif动画,所以在ImageViewModel里面,我又用了一系列的tricky来处理gif动画的渲染。
if (string.Compare(".gif", Path.GetExtension(ImageUrl), true) == 0) { GIFImageControl g = new GIFImageControl(); g.Stretch = System.Windows.Media.Stretch.Uniform; g.StretchDirection = StretchDirection.Both; g.AnimatedImageControl(ImageUrl); result = g; }
GIFImageControl这个第三方的类处理了gif的动画问题,不过这里又引入了两个还没有解决的问题。
第一个是因为GIFImageControl这个类并不是标准的WPF Image类,所以它失去了stretch的功能,那就是说,所有gif的图片都不能在RIV上拉伸,而只能以原始大小显示。
第二个是,这个类本来只需要用来处理包含动画的gif,但是目前只采用了文件后缀判断,所以不包含动画的gif也会用这个类来渲染,而某些被强制改了后缀的gif动画却不能得到显示。
好了,DataModel和ViewModel的大致介绍就这么多,下一篇是关于GUI的实现的描述。
本篇对应代码下载:#53865
相关文章:
人间风景(Renjian Image Viewer, RIV)最新版本预览
人间风景开发日志 – 1 <介绍,文件结构>
相关文章推荐
- 人间风景开发日志 – 1 <介绍,文件结构>
- 具有键“XXX”的 ViewData 项属于类型“System.Int32”,但它必须属于类型“IEnumerable<SelectListItem>
- Objective-C ,ios,iphone开发基础:多个视图(view)之间的切换,以及视图之间传值。使用parent <->dismiss
- “~/Views/Login/Login.aspx”处的视图必须派生自 ViewPage、ViewPage<TModel>、ViewUserControl 或 ViewUserControl<TModel>。
- 开发日志:<s:select>标签显示从后台传过来的空格问题
- 不存在具有键“xxxId”的“IEnumerable<SelectListItem>”类型的 ViewData 项
- 开发日志:<table>的<td>标签的行高无法设置为10px以下
- 无法将类型“System.Data.Entity.Infrastructure.DbQuery<TZM.TROA.Model.RoleInfo>”转换为“System.Collections.Gene
- 2016-12-03(两种处理JSON返回页面的方式、分页,ModelAndView和Model的区别,<C:forEach>注意)
- IntraWeb下Model-View-Presenter开发实战--传递篇之一(DataTransferObject)
- 乐呵开发日志<一>
- Android开发-API指南-<data>
- MVC View中Model是List<dynamic>时不能使用Html.DisplayFor
- 开发日志整理<序>(5/2013-至今)
- Android开发艺术探索<View的点击事件触发过程>
- Android开发-API指南-<data>
- ASP.NET MVC - The view must derive from WebViewPage, or WebViewPage<TModel>
- Android开发问题积累 <加载在线Gif><WebView无法加载网页图片>
- android WebView开发总结<续>
- 不存在具有“AppType”的“IEnumerable<SelectListItem>”类型的 ViewData 项