65.9K
CodeProject 正在变化。 阅读更多。
Home

Silverlight MVVM 和通过 WCF 进行验证

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.18/5 (4投票s)

2013年6月5日

CPOL

3分钟阅读

viewsIcon

19789

downloadIcon

578

Silverlight WCF 启用项目的输入验证示例

Sample Image - maximum width is 600 pixels

引言

本文介绍如何在简单的 POCO(普通 CLR 对象)中添加和启用验证逻辑,以及 Silverlight 客户端如何通过 WCF 数据服务使用它们。

背景

我写这篇文章是因为在 Silverlight .NET 中创建一个简单的验证测试项目时,应用于我的模型的验证规则没有在 WCF 服务的消费者端(在本例中,是 Silverlight 客户端)触发。我想知道为什么当我的 WCF 数据服务被客户端使用时,这些规则没有被触发,并得出结论:客户端上由代理创建的引用模型类不包含我添加到模型类中的验证属性。本文向您展示了解决此问题的一种可能方案。

架构

示例应用程序代表典型的 MVVM(模型-视图-视图模型)架构。我将简要解释嵌入在解决方案中的不同项目。

  • MVVM_Base: 基础 ViewModel 项目,它公开了一些用于启用 MVVM 架构和验证的类。
  • MVVM_DataService: 公开可由客户端使用的 WCF 服务。
  • MVVM_Model_SL: Silverlight 类库,其中包含我们的模型类。
  • MVVM_MyValidation: Silverlight 客户端应用程序。
  • MVVM_MyValidation.Web: 托管网站。
深入解释 MVVM 模式超出了本文的范围。因此,读者应该熟悉基本的 MVVM 概念。

模型

我保持模型非常简单,只包含两个带有简单属性验证的属性。验证触发逻辑封装在 ValidatingViewModelBase 类中,它是 MVVM 基础项目的一部分。

 public class Employee : ValidatingViewModelBase
 {
     private string _firstName;

     [Required(ErrorMessage="Firstname is required!")]
     public string FirstName
     {
         get { return _firstName; }
         set { _firstName = value; OnPropertyChanged("FirstName"); }
     }

     private string _lastName;

     [Required(ErrorMessage = "Lastname is required!")]
     public string LastName
     {
         get { return _lastName; }
         set { _lastName = value; OnPropertyChanged("LastName"); }
     }
 }
如果你查看 MVVM_Model_SL 项目的代码(在 zip 文件中提供),你会注意到我添加了 MVVM 基类的链接。 我不得不这样做,因为我将 MVVM_Base 项目实现为一个普通的类库(而不是一个特定的 Silverlight 类库),所以我可以在其他项目中重用我的 MVVM 实现。添加链接是必要的,因为你不能在 Silverlight 类库项目中引用一个普通的类库。

数据服务

  • 该服务是一个 WCF 服务,它实现了 IEmployeeService 并公开了方法 GetEmployees
  • 实现类返回一个员工对象列表。
using MVVM_Model_SL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace MVVM_DataService
{
    [ServiceContract]
    public interface IEmployeeService
    {
        [OperationContract]
        List<employee /> GetEmployees();
    }

}
using MVVM_Model_SL;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.ServiceModel;
using System.Text;

namespace MVVM_DataService
{
    public class EmployeeService : IEmployeeService
    {

        public List<employee /> GetEmployees()
        {
            return
            new List<employee />(){
                new Employee{FirstName="Marc",LastName="Spencer"},
                new Employee{FirstName="Julie",LastName="Matthews"};
        }
    }
}

ViewModel

  • ViewModel 是我们的 Silverlight 应用程序的一部分,它是 View 和我们的 WCF 数据服务之间的桥梁。
  • View 通过 ViewModel 进行通信并获取其数据。
  • ViewModel 中的代码非常不言自明。
namespace MVVM_MyValidation.ViewModels
{
    public class EmployeeViewModel : MVVM_Base.ValidatingViewModelBase
    {
        #region Storage

        // Instance of the Service Client
        private EmployeeServiceClient _serviceClient;

        // Holds the returned employees as an Observable Collection
        private ObservableCollection<employee /> _employeeList;
        public ObservableCollection<employee /> EmployeeList
        {
            get { return _employeeList; }
            set { _employeeList = value; OnPropertyChanged("EmployeeList"); }
        }

        #endregion Storage

        #region Ctor

        public EmployeeViewModel()
        {
            // Create the Service client a get the employees
            _serviceClient = new EmployeeServiceClient();
            RefreshEmployees();
        }

        #endregion Ctor

        #region Public Interface

        // Get the Number of Employees in the Collection
        public Int32 NumberOfEmployees
        {
            get { return _employeeList.Count; }
        }

        // Set/Get the Current Employee
        private Employee _currentEmployee;
        public Employee CurrentEmployee
        {
            get { return _currentEmployee; }
            set { _currentEmployee = value; OnPropertyChanged("CurrentEmployee"); }
        }

        #endregion Public Interface

        #region Private Interface

        // Get the Employee List from the Service &
        // point to the first employee. This is done in an Async Way.
        private void RefreshEmployees()
        {
            _serviceClient.GetEmployeesCompleted += (s, e) =>
                {
                    EmployeeList = e.Result;
                    CurrentEmployee = EmployeeList.Count > 0 ? EmployeeList[0] : null;
                };

            _serviceClient.GetEmployeesAsync();
        }

        #endregion Private Interface
    }
}

View

  • View 是 Silverlight 应用程序的一部分。
  • View 将其 DataContext 设置为 ViewModel
namespace MVVM_MyValidation.Views
{
    public partial class EmployeeView : Page
    {
        private EmployeeViewModel _viewModel;

        public EmployeeView()
        {
            InitializeComponent();
            _viewModel = new EmployeeViewModel();

            Loaded += (s, e) =>
                {
                    DataContext = _viewModel;
                };
        }

        // Executes when the user navigates to this page.
        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
        }
    }
}

一旦 DataContext 被设置,View 就可以通过 .NET 中的 databinding 功能轻松地绑定到它的属性。下面的代码片段突出显示并记录了最重要的部分

Click to enlarge image

  • DataGrid 绑定到我们的 ViewModel 公开的 EmployeeList
  • DataColumns 绑定到 Employee 公开的属性。
  • CurrentEmployee 保存对 DataGrid 中当前选定的 Employee 的引用。
  • TextBoxes 绑定到 CurrentEmployee 的属性。

我们的 View 绑定中最有趣的部分是详细信息列,它允许用户修改当前 Employee 属性的内容。事实上,验证异常在绑定的属性上被激活(通过 ValidatesOnDataErrorsValidatesOnExceptions 属性)。 奇怪的是,除非你显式地将模型作为引用添加到项目,并将服务引用配置为重用所有引用程序集中的类型,否则验证将不会被触发。原因是引用的生成的代理代码不包含客户端的验证代码。因此,你必须以某种方式“绕过”这个生成的类,方法是将原始模型类作为引用添加到客户端项目,并确保服务代理引用被配置为重用所有引用程序集中的所有类型。这样,GUI 将绑定到模型类而不是生成的代理类。由于原始模型类包含验证属性,因此将发生数据验证。实现此目的的配置步骤如下所示

*步骤 1:将模型作为引用添加到客户端项目

*步骤 2:配置服务引用以重用所有引用程序集中的类型

就这样,各位!

© . All rights reserved.