zoukankan      html  css  js  c++  java
  • SilverLight Tip 1 : Validation

    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

  • 相关阅读:
    [BZOJ]2589: Spoj 10707 Count on a tree II
    [BZOJ]2434: [Noi2011]阿狸的打字机
    Codeforces Round #408 (Div. 2)
    [BZOJ]2653: middle
    洛谷4月月赛R1
    2017省夏令营Day8
    2017省夏令营Day7
    2017省夏令营Day6
    【20170604校内模拟赛】香蕉
    【20170602模拟赛】秋之国的夏日祭
  • 原文地址:https://www.cnblogs.com/luminji/p/2084650.html
Copyright © 2011-2022 走看看