SilverLight Tip 1 : Validation

简介: 1:SL的数据验证和WPF的不同 首先,很遗憾,SL中不再存在ValidationRules,要在SL中绑定时验证数据,并且显示在UI,只能依赖于NotifyOnValidationError=True, ValidatesOnExceptions=True这两个属性,如下: 如果要查看WPF的数据验证的方式,可以查看该文《WPF快速指导5:验证》。

1:SL的数据验证和WPF的不同

首先,很遗憾,SL中不再存在ValidationRules,要在SL中绑定时验证数据,并且显示在UI,只能依赖于NotifyOnValidationError=True, ValidatesOnExceptions=True这两个属性,如下:

image

如果要查看WPF的数据验证的方式,可以查看该文《WPF快速指导5:验证》。

2:一般情况下的验证

一般情况下,UI绑定数据类型的属性,如在上图中,绑定的就是Name和Age,它在UI的VIEWMODEL中,如下:

    public class MainPageVM : INotifyPropertyChanged
    {
        public MainPageVM()
        {
        }

        private string name = "luminji";

        public string Name
        {
            get { return name; }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new Exception("姓名不能为空");
                }
                name = value;
                OnPropertyChanged("Name");
            }
        }

        private int age = 1;

        public int Age
        {
            get { return age; }
            set
            {
                if (value > 100)
                {
                    throw new Exception("年龄必须小与100");
                }
                age = value;
                OnPropertyChanged("Age");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler pceh = PropertyChanged;
            if (pceh != null)
            {
                pceh(this, new PropertyChangedEventArgs(propertyName));
            }
        }
       
    }

采用UI直接绑定VM的属性,如果Age>100,则UI会提示出现输入有误。

 

3:绑定实体类型

不过,如果属性很多,我们就会考虑绑定实体类型。如User,而这个实体类,是在服务器端的,形如:

    public class User
    {
        private string name = "luminji";

        public string Name
        {
            get { return name; }
            set
            {
                name = value;
            }
        }

        private int age = 1;

        public int Age
        {
            get { return age; }
            set
            {
                age = value;
            }
        }
    }

比如,我们使用的是Ria Service。Ria Service有可能是从DAL层获取数据并开放接口给客户端。我们都知道,客户端的代码都是自动生成的,自动生成的代码在SL项目的Generated_Code目录下的(SL项目名).Web.g.cs文件下。所以,最终User类型在客户端的代理形式为:

    /// <summary>
    /// The 'User' entity class.
    /// </summary>
    [DataContract(Namespace="http://schemas.datacontract.org/2004/07/SilverlightApplication3.Web.Model")]
    public sealed partial class User : Entity
    {
        
        private int _age;
        
        private string _name;
        
        #region Extensibility Method Definitions

        /// <summary>
        /// This method is invoked from the constructor once initialization is complete and
        /// can be used for further object setup.
        /// </summary>
        partial void OnCreated();
        partial void OnAgeChanging(int value);
        partial void OnAgeChanged();
        partial void OnNameChanging(string value);
        partial void OnNameChanged();

        #endregion
        
        
        /// <summary>
        /// Initializes a new instance of the <see cref="User"/> class.
        /// </summary>
        public User()
        {
            this.OnCreated();
        }
        
        /// <summary>
        /// Gets or sets the 'Age' value.
        /// </summary>
        [DataMember()]
        public int Age
        {
            get
            {
                return this._age;
            }
            set
            {
                if ((this._age != value))
                {
                    this.OnAgeChanging(value);
                    this.RaiseDataMemberChanging("Age");
                    this.ValidateProperty("Age", value);
                    this._age = value;
                    this.RaiseDataMemberChanged("Age");
                    this.OnAgeChanged();
                }
            }
        }
        
        /// <summary>
        /// Gets or sets the 'Name' value.
        /// </summary>
        [DataMember()]
        [Editable(false, AllowInitialValue=true)]
        [Key()]
        [RoundtripOriginal()]
        public string Name
        {
            get
            {
                return this._name;
            }
            set
            {
                if ((this._name != value))
                {
                    this.OnNameChanging(value);
                    this.ValidateProperty("Name", value);
                    this._name = value;
                    this.RaisePropertyChanged("Name");
                    this.OnNameChanged();
                }
            }
        }
        
        /// <summary>
        /// Computes a value from the key fields that uniquely identifies this entity instance.
        /// </summary>
        /// <returns>An object instance that uniquely identifies this entity instance.</returns>
        public override object GetIdentity()
        {
            return this._name;
        }
    }

这个时候,如果我们在UI中继续绑定这个实体类型,势必会丢掉UI异常通知的行为,因为,显然,我们不能跑到这个客户端的代理类中throw new Exception("姓名不能为空"); ,那会在下一次代码自动生成的时候被覆盖掉。

4:解决方案之建立映射

一种解决方案是我们的UI仍旧不绑定实体类型,而是为类型的属性在ViewModel中建立一一映射的关系,如下:

    public class MainPageVM : INotifyPropertyChanged
    {
        public MainPageVM()
        {
            user = new User();
            serviceUser = new DomainServiceUser();
            serviceUser.Load<User>(serviceUser.GetAUserQuery(), new Action<System.ServiceModel.DomainServices.Client.LoadOperation<User>>(this.GetAUserCallBack), null);
        }

        DomainServiceUser serviceUser;
        User user;
        
        
        void GetAUserCallBack(LoadOperation<User> arg)
        {
            user = (arg.Entities as IList<User>)[0];
            Name = user.Name;
            Age = user.Age;
        }


        public string Name
        {
            get { return user.Name; }
            set
            {
                if (string.IsNullOrEmpty(value))
                {
                    throw new Exception("姓名不能为空");
                }
                user.Name = value;
                OnPropertyChanged("Name");
            }
        }


        public int Age
        {
            get { return user.Age; }
            set
            {
                if (value > 100)
                {
                    throw new Exception("年龄必须小与100");
                }
                user.Age = value;
                OnPropertyChanged("Age");
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler pceh = PropertyChanged;
            if (pceh != null)
            {
                pceh(this, new PropertyChangedEventArgs(propertyName));
            }
        }
       
    }

UI效果图:

image

到此位置的源码下载为:SilverlightApplication20110618.zip

5:解决方案之使用ValidationSummary

使用ValidationSummary,需要我们引入程序集System.Windows.Controls.Data.Input,在UI前台,我们需要安置一个ValidationSummary:

image

接着,我们让前台的ValidationSummary的Errors赋值给VM。

    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
            ViewModel = new MainPageVM(this.vs.Errors);
        }

        public MainPageVM ViewModel
        {
            get
            {
                return (MainPageVM)this.DataContext;
            }
            set
            {
                this.DataContext = value;
            }
        }

        private void btnSave_Click(object sender, RoutedEventArgs e)
        {

        }
    }

我们还需要为UI绑定一些Command,以便在需要验证输入的时候,让VM去判断是否有错误发生。一旦有错误发生,则为Errors添加错误项。

    public class MainPageVM : INotifyPropertyChanged
    {
        public MainPageVM(ObservableCollection<ValidationSummaryItem> errors)
        {
            m_errors = errors;
            Click = new ActionCommand(this.OnClick);
            serviceUser = new DomainServiceUser();
            serviceUser.Load<User>(serviceUser.GetAUserQuery(), new Action<System.ServiceModel.DomainServices.Client.LoadOperation<User>>(this.GetAUserCallBack), null);
            //serviceUser.Load<User>(serviceUser.GetAUserQuery(), LoadBehavior.RefreshCurrent, new Action<System.ServiceModel.DomainServices.Client.LoadOperation<User>>(this.GetAUserCallBack), null);
        }

        DomainServiceUser serviceUser;
        User user;
        ObservableCollection<ValidationSummaryItem> m_errors;

        void GetAUserCallBack(LoadOperation<User> arg)
        {
            user = (arg.Entities as IList<User>)[0];
            OnPropertyChanged("User");
        }

        public User User
        {
            get { return user; }
            set
            {
                user = value;
                OnPropertyChanged("User");
            }
        }

        public ICommand Click { get; private set; }

        public void OnClick(object arg)
        {
            m_errors.Clear();
            if (User.Age > 100)
            {
                m_errors.Add(new ValidationSummaryItem("年龄不能大雨100"));
            }
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler pceh = PropertyChanged;
            if (pceh != null)
            {
                pceh(this, new PropertyChangedEventArgs(propertyName));
            }
        }

    }

最后的运行结果为:

image

备注:要让实体类在SL端支持EDIT,必须要让DomainService针对该实体类支持开放GUID接口。如下:

    [EnableClientAccess()]
    public class DomainServiceUser : DomainService
    {
        [Query]
        public IList<User> GetUsers()
        {
            return new List<User>()
            {
                new User() { Name = "huzhonghua", Age = 99 }
            };
        }

        public User GetAUser()
        {

            return new User() { Name = "luminji", Age = 98 };
        }

        [Delete]
        public void DeleteUser(User user)
        {
            throw new NotImplementedException();
        }

        [Insert]
        public void InsertUser(User user)
        {
            throw new NotImplementedException();
        }

        [Update]
        public void UpdateUser(User user)
        {
            throw new NotImplementedException();
        }

    }

本文源码下载:SilverlightApplication2001061902.zip

Creative Commons License本文基于 Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名 http://www.cnblogs.com/luminji(包含链接)。如您有任何疑问或者授权方面的协商,请给我留言。
目录
相关文章
|
3月前
|
监控 负载均衡 安全
WebSocket网络编程深度实践:从协议原理到生产级应用
蒋星熠Jaxonic,技术宇宙中的星际旅人,以代码为舟、算法为帆,探索实时通信的无限可能。本文深入解析WebSocket协议原理、工程实践与架构设计,涵盖握手机制、心跳保活、集群部署、安全防护等核心内容,结合代码示例与架构图,助你构建稳定高效的实时应用,在二进制星河中谱写极客诗篇。
WebSocket网络编程深度实践:从协议原理到生产级应用
|
SQL 机器学习/深度学习 自然语言处理
Text-to-SQL技术演进 - 阿里云OpenSearch-SQL在BIRD榜单夺冠方法剖析
本文主要介绍了阿里云OpenSearch在Text-to-SQL任务中的最新进展和技术细节。
|
Ubuntu 搜索推荐 Linux
Linux的Vim编辑器详解
Linux的Vim编辑器详解
|
5天前
|
人工智能 JavaScript Linux
【Claude Code 全攻略】终端AI编程助手从入门到进阶(2026最新版)
Claude Code是Anthropic推出的终端原生AI编程助手,支持40+语言、200k超长上下文,无需切换IDE即可实现代码生成、调试、项目导航与自动化任务。本文详解其安装配置、四大核心功能及进阶技巧,助你全面提升开发效率,搭配GitHub Copilot使用更佳。
|
6天前
|
存储 人工智能 自然语言处理
OpenSpec技术规范+实例应用
OpenSpec 是面向 AI 智能体的轻量级规范驱动开发框架,通过“提案-审查-实施-归档”工作流,解决 AI 编程中的需求偏移与不可预测性问题。它以机器可读的规范为“单一真相源”,将模糊提示转化为可落地的工程实践,助力开发者高效构建稳定、可审计的生产级系统,实现从“凭感觉聊天”到“按规范开发”的跃迁。
860 13
|
3天前
|
云安全 安全
免费+限量+领云小宝周边!「阿里云2026云上安全健康体检」火热进行中!
诚邀您进行年度自检,发现潜在风险,守护云上业务连续稳健运行
1166 1
|
5天前
|
人工智能 JavaScript 前端开发
【2026最新最全】一篇文章带你学会Cursor编程工具
本文介绍了Cursor的下载安装、账号注册、汉化设置、核心模式(Agent、Plan、Debug、Ask)及高阶功能,如@引用、@Doc文档库、@Browser自动化和Rules规则配置,助力开发者高效使用AI编程工具。
722 4
|
6天前
|
消息中间件 人工智能 Kubernetes
阿里云云原生应用平台岗位急招,加入我们,打造 AI 最强基础设施
云原生应用平台作为中国最大云计算公司的基石,现全面转向 AI,打造 AI 时代最强基础设施。寻找热爱技术、具备工程极致追求的架构师、极客与算法专家,共同重构计算、定义未来。杭州、北京、深圳、上海热招中,让我们一起在云端,重构 AI 的未来。
|
9天前
|
IDE 开发工具 C语言
【2026最新】VS2026下载安装使用保姆级教程(附安装包+图文步骤)
Visual Studio 2026是微软推出的最新Windows专属IDE,启动更快、内存占用更低,支持C++、Python等开发。推荐免费的Community版,安装简便,适合初学者与个人开发者使用。
985 11

热门文章

最新文章