在服务器上使用Web应用程序管理RSS文件时,本文介绍的应用非常有用。该应用程序托管在CodePlex上,网址为 。这是三部分文章中的第三部分,将描述这个应用程序:
思考Silverlight的方式!
当使用Silverlight工作时,必须以与典型Web开发不同的方式思考,现在有一个客户端和一个服务器,它们可以以某种方式连接(使用Web服务或其他方式)。如果不熟悉Silverlight,建议先去了解它,因为本文不打算解释Silverlight是什么。通常,当阅读或观看有关Silverlight数据绑定的示例时,这些示例通常是绑定到数据库或绑定到实体框架对象。至于其他数据源,例如XML文件,没有找到任何标准或现成的技术可以直接使用。因此,尝试探索在Silverlight中绑定XML文件的不同方式,将讨论可选方案,选择的方案,以及最重要的原因。
随着XAML在WPF和Silverlight中的引入,微软打算明确区分视图(或如何呈现数据)和可能需要在这些数据上执行的任何其他逻辑或过程,以增加应用程序的解耦和可重用性,视图应该始终关心如何呈现数据,仅此而已。
但是,这是MVC中视图的工作,那么MVVM的区别是什么呢?
区别很简单,模型中呈现的数据总是依赖于某些数据源,无论是数据库中的表、XML模式还是其他东西。然而,这些数据可以以不同的视角查看。可以有一个模型作为客户,然后需要根据不同的位置、销售或订单等查看这个客户,等等... 在MVVM之前,最终会在视图中编写一些代码来根据偏好进行过滤。
在MVVM中,只需简单地定义一个ViewModel来根据选择过滤数据,视图就不必处理这个问题。
这就是MVVM与MVC不同的原因之一,另一个原因是技术本身导致了MVVM,如果比较传统的ASP或Windows表单绑定和事件处理程序,几乎不可能有一个没有任何代码的Windows表单或ASP.NET页面。
可能会问,为什么要这样做?
答案很简单,因为它是一个WEB页面,它是WINDOWS表单,它是一个视图。它不是应用程序的逻辑。那么,为什么要这样做呢?只是在查看数据?为什么不让视图有一种技术来插入想要提供的任何功能,例如,点击客户时。所以,这里引入了XAML中的命令和数据上下文的整个概念,以支持MVVM。
将使用核心组件使用MVVM模式为Silverlight应用程序提供数据。首先让探索将数据绑定到Silverlight应用程序的不同方式:
第一个选项在案例中并不适用,因为没有实体框架数据源。第四个选项工作量太大(重新发明轮子)。有机会实现IQuerable数据源,或者选择一个简单的WCF Web服务,选择了后者。它看起来工作量更少。
WCF Web服务实际上很简单,只是封装了控制器RSSFeedXLinqController来加载或保存特定文件。
C# [OperationContract] public RSSFeed GetRssFeed(int FileID) { DomainServiceDB d = new DomainServiceDB(); File f = d.GetFileByID(FileID); if (HttpContext.Current.User.Identity.IsAuthenticated) if (HttpContext.Current.User.IsInRole(f.aspnet_Roles.RoleName)) return new RSSFeedXLinqController().LoadRss(f.FileURL); else throw new Exception("Access Denied"); return null; }
RSSViewModel实现了INotifyPropertyChanged,以通知视图控件数据的任何更改。RssViewModel包含一个Feed对象,这是模型,一个Load命令和Save命令,以及一个PagedCollectionView,这是用于RSSItem的,使用这个对象来允许分页。
C# public class RSSViewModel: INotifyPropertyChanged { private RSSFeed feed; private bool isChanged; public bool IsChanged {...} WCFRSSDataSourceClient client; public DelegateCommand LoadCommand { get; set; } private PagedCollectionView itemsPaged; public PagedCollectionView ItemsPaged {...} public DelegateCommand SaveCommand { get; set; } public RSSFeed Feed {...} public event PropertyChangedEventHandler PropertyChanged; ... The main methods in this class are to Load and Save the file which is simply establishing the connection with the Web Service. C# private void LoadRSS(object Parameter) { client = new WCFRSSDataSourceClient("CustomBinding_WCFRSSDataSource1"); client.GetRssFeedCompleted += new EventHandler(client_GetRssFeedCompleted); client.GetRssFeedAsync(((File)App.Current.Resources["File"]).FileID); } public void SaveRSS(object Parameter) { client = new WCFRSSDataSourceClient("CustomBinding_WCFRSSDataSource1"); client.UpdateRssFeedCompleted += new EventHandler(client_UpdateRssFeedCompleted); client.UpdateRssFeedAsync(feed, ((File)App.Current.Resources["File"]).FileID); ... }
至于其他管理页面,例如管理文件和管理角色,使用了领域数据服务来绑定到数据源。
人们可能会争论领域数据服务是否支持MVVM?否应该为领域数据服务实现一个ViewModel?个人认为,这取决于情况;如果要按原样查看模型,那么没有必要制作一个ViewModel只是为了模拟模型并建立连接,因为XAML中实现了一个嵌入式机制来声明领域数据源,所以自从模式是为了让生活更轻松以来,像管理角色和管理文件这样的页面不会有任何ViewModel,而且仍然可以打开代码后面并看到它仍然是空的。所以仍然遵循无代码视图的概念。然而,在其他情况下,例如主页案例,需要根据登录的用户查看文件,为领域服务创建了一个ViewModel来过滤用户。
在使用领域数据服务绑定到数据表单中的组合框时,遇到了一个值得一提问题。出于某种原因,当用户更改组合框时,这个组合框的键值并没有改变。一直在寻找解决方案,几乎花了4个小时才找到。要绑定数据表单中的组合框,请按照以下步骤操作:
XML <combobox name="combobox2" itemssource="{Binding Source={StaticResource RoleSource}, Path=Data, Mode=OneWay}" selecteditem="{Binding Path=RoleID, Mode=TwoWay, Converter={StaticResource RoleConverter}, NotifyOnValidationError=True, ValidatesOnExceptions=True}" displaymemberpath="RoleName" selectedvaluepath="RoleId" />
项目源应该绑定到包含键和值的数据源,并使用单向绑定模式。
显示成员路径应该包含值字段名称。
选定值路径应该包含键值字段。
最重要的是,应该定义一个转换器,它将接受键(案例中的项目ID)并返回项目对象,反之亦然。