博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WPF3.5 使用BINDINGGROUP进行实体类和集合验证
阅读量:5108 次
发布时间:2019-06-13

本文共 16723 字,大约阅读时间需要 55 分钟。

介绍了自定义或系统自带的ValidationRule进行验证,这种方法对于单个元素的验证不错。很多时候,我们需要对表单(Form)进行验证,也就是对一个实体类进行验证,或者对一个集合的每项进行验证,则显得不尽人意(每次只能验证一次)。WPF3.5中提供了BindingGroup用来验证多个绑定元素,可以对表单(form)和实体类进行验证。另外BindingGroup提供了Transcational的支持,就是说可以让操作回滚(BeginEdit,CancelEdit,CommitEdit)。BindingGroup的验证是同时进行的。可以设置BindingGroupName把一个Binding加入已存在的BindingGroup(就是BindingGroupName指定的)。

MSDN上是这样说的:

BindingGroup 在多个绑定之间创建关系,从而可一起验证和更新这些绑定。例如,假定某应用程序提示用户输入地址。然后该应用程序使用用户提供的值填充 Address 类型的对象,该对象具有 Street、City、ZipCode 和 Country 属性。该应用程序有一个包含四个  控件的面板,其中每个控件均数据绑定到对象的属性之一。可以使用 BindingGroup 中的  验证 Address 对象。如果绑定加入相同的 BindingGroup,则可以确保邮政编码对于地址所在国家/地区有效。

设置  或  上的  属性。正如任何其他可继承属性一样,子元素从其父元素继承 BindingGroup。如果发生以下情况之一,则会将子代元素上的绑定添加到 BindingGroup:

  • 绑定的源和具有 BindingGroup 的元素的  是同一对象,并且未设置  属性。

  • 绑定的  属性等于  的 ,并且它们没有显式设置为 null引用(在 Visual Basic 中为 Nothing)。

在地址示例中,假定将  的  设置为 Address 类型的对象。每个  的绑定均添加到面板的 BindingGroup 中。

将  对象添加到 BindingGroup 中。在运行  时,将 BindingGroup 作为  方法的第一个参数传递。可以使用该 BindingGroup 上的  或  方法获取对象的建议值,使用  属性获取绑定的源。

BindingGroup 在同一时间更新绑定的源,而不是分别更新每个绑定。在调用任一方法(、 或 )验证数据时,将验证并可能会更新示例中的每个  的绑定。当绑定是 BindingGroup 的一部分时,除非显式设置  属性,否则在对 BindingGroup 调用  或  之前,不会更新绑定的源。

BindGroup常用成员:

public class BindingGroup : DependencyObject{  public Collection
BindingExpressions { get; } public bool CanRestoreValues { get; } public IList Items { get; } public string Name { get; set; } public bool NotifyOnValidationError { get; set; } public Collection
ValidationRules { get; } public void BeginEdit(); public void CancelEdit(); public bool CommitEdit(); public object GetValue(object item, string propertyName); public bool TryGetValue(object item, string propertyName, out object value); public bool UpdateSources(); public bool ValidateWithoutUpdate();}
 
Items: 中的绑定对象所使用的源,是个List。所有作为源的对象都会被包含在Items中。通常,Items 中只有一项,即作为使用  的元素的  的对象。
但是, 也可以包含多个源。例如,如果绑定对象共享同一  但使用不同的源对象,则用作源的每个对象均在 Items 中。 如果绑定路径可解析为源的嵌套属性,则 Items 中也可有多个对象。例如,假定  控件的绑定是  的一部分,并且其  是 Customer 对象,该对象具有 Address 类型的属性。 如果  的  为 Address.ZipCode 属性,则 Address 会添加到 Items 属性中。
 
NotifyOnValidationError:获取或设置在  的状态更改时是否发生  事件。
 
BeginEdit:开始编辑事务。
 
CommitEdit:运行所有的Rule,如果成功,则保存更改,更新源。
 
CancelEdit:取消更改。
 
以上三个,如果源对应的类继承自, 会调用中的相应方法。
 
UpdateSources:运行所有ValidationStep设置为、 或 的Rule。如果成功,更新源。此方法不会挂起事务并结束事务,也就是说调用完该方法后事务还是处于运行中。
 
ValidateWithoutUpdate:如同UpdateSources,但是不会更新源。
 
所以有三个方法可以用作验证:CommitEdit,UpdateSources,ValidateWithoutUpdate。

先看看验证实体类的示例:

This sample demonstrates how to validate an object by checking multiple properties in a ValidationRule. When a ValidationRule is added to a BindingGroup, the rule can get the properties of the source item in the Validate method.
This sample checks that if an item costs more than 100 dollars, the item is available for at least 7 days.
 
void stackPanel1_Loaded(object sender, RoutedEventArgs e)        {            // Set the DataContext to a PurchaseItem object.            // The BindingGroup and Binding objects use this as            // the source.            stackPanel1.DataContext = new PurchaseItem();            // Begin an edit transaction that enables            // the object to accept or roll back changes.            stackPanel1.BindingGroup.BeginEdit();        }        private void Submit_Click(object sender, RoutedEventArgs e)        {            //验证并提交
if (stackPanel1.BindingGroup.CommitEdit())            {                MessageBox.Show("Item submitted");                //提交成功后继续接收edit信息
stackPanel1.BindingGroup.BeginEdit();            }        }        private void Cancel_Click(object sender, RoutedEventArgs e)        {            // Cancel the pending changes and begin a new edit transaction.            stackPanel1.BindingGroup.CancelEdit();            stackPanel1.BindingGroup.BeginEdit();        }        // This event occurs when a ValidationRule in the BindingGroup        // or in a Binding fails.        private void ItemError(object sender, ValidationErrorEventArgs e)        {            if (e.Action == ValidationErrorEventAction.Added)//描述是添加还是清除了  对象            {                MessageBox.Show(e.Error.ErrorContent.ToString());            }        }

 

      ValidationRule文件:

public class ValidateDateAndPrice : ValidationRule    {        // Ensure that an item over $100 is available for at least 7 days.        public override ValidationResult Validate(object value, CultureInfo cultureInfo)        {            BindingGroup bg = value as BindingGroup;            // Get the source object.            PurchaseItem item = bg.Items[0] as PurchaseItem;                        object doubleValue;            object dateTimeValue;            // Get the proposed values for Price and OfferExpires.            bool priceResult = bg.TryGetValue(item, "Price", out doubleValue);            bool dateResult = bg.TryGetValue(item, "OfferExpires", out dateTimeValue);            if (!priceResult || !dateResult)            {                return new ValidationResult(false, "Properties not found");            }            double price = (double)doubleValue;            DateTime offerExpires = (DateTime)dateTimeValue;            // Check that an item over $100 is available for at least 7 days.            if (price > 100)            {                if (offerExpires < DateTime.Today + new TimeSpan(7, 0, 0, 0))                {                    return new ValidationResult(false, "Items over $100 must be available for at least 7 days.");                }            }            return ValidationResult.ValidResult;        }    }        //Ensure that the price is positive.    public class PriceIsAPositiveNumber : ValidationRule    {        public override ValidationResult Validate(object value, CultureInfo cultureInfo)        {            try            {                double price = Convert.ToDouble(value);                if (price < 0)                {                    return new ValidationResult(false, "Price must be positive.");                }                else                {                    return ValidationResult.ValidResult;                }            }            catch (Exception)            {                // Exception thrown by Conversion - value is not a number.                return new ValidationResult(false, "Price must be a number.");            }        }    }    // Ensure that the date is in the future.    class FutureDateRule : ValidationRule    {        public override ValidationResult Validate(object value, CultureInfo cultureInfo)        {            DateTime date;            try            {                date = DateTime.Parse(value.ToString());            }            catch (FormatException)            {                return new ValidationResult(false, "Value is not a valid date.");            }            if (DateTime.Now.Date > date)            {                return new ValidationResult(false, "Please enter a date in the future.");            }            else            {                return ValidationResult.ValidResult;            }        }    }    // PurchaseItem implements INotifyPropertyChanged and IEditableObject    // to support edit transactions, which enable users to cancel pending changes.    public class PurchaseItem : INotifyPropertyChanged, IEditableObject    {        struct ItemData        {            internal string Description;            internal double Price;            internal DateTime OfferExpires;            static internal ItemData NewItem()            {                ItemData data = new ItemData();                data.Description = "New item";                data.Price = 0;                data.OfferExpires = DateTime.Now + new TimeSpan(7, 0, 0, 0);                return data;            }        }        ItemData copyData = ItemData.NewItem();        ItemData currentData = ItemData.NewItem();        public PurchaseItem()        {        }        public PurchaseItem(string desc, double price, DateTime endDate)        {            Description = desc;            Price = price;            OfferExpires = endDate;        }        public override string ToString()        {            return String.Format("{0}, {1:c}, {2:D}", Description, Price, OfferExpires);        }        public string Description        {            get { return currentData.Description; }            set            {                if (currentData.Description != value)                {                    currentData.Description = value;                    NotifyPropertyChanged("Description");                }            }        }        public double Price        {            get { return currentData.Price; }            set            {                if (currentData.Price != value)                {                    currentData.Price = value;                    NotifyPropertyChanged("Price");                }            }        }        public DateTime OfferExpires        {            get { return currentData.OfferExpires; }            set            {                if (value != currentData.OfferExpires)                {                    currentData.OfferExpires = value;                    NotifyPropertyChanged("OfferExpires");                }            }        }        #region INotifyPropertyChanged Members        public event PropertyChangedEventHandler PropertyChanged;        private void NotifyPropertyChanged(String info)        {            if (PropertyChanged != null)            {                PropertyChanged(this, new PropertyChangedEventArgs(info));            }        }        #endregion        #region IEditableObject Members        public void BeginEdit()        {            copyData = currentData;        }        public void CancelEdit()        {            currentData = copyData;            NotifyPropertyChanged("");        }        public void EndEdit()        {            copyData = ItemData.NewItem();        }        #endregion    }
此例中PurchaseItem继承了IEditableObject,那么BindingGroup使用的BeginEdit,CancelEdit, EndEdit会使用IEditableObject中的相应方法。
 

对集合的验证:

下例点击Add Customer时,验证通过后会在集合中增加一个Customer对象,要求Customer所在区域与客服代表所在区域一致。
 
 
This sample demonstrates how to validate an object in an ItemsControl. The ValidationRule assigned to ItemsControl.ItemBindingGroup checks multiple properties in the item. This sample checks that a customer is assigned to a sales representative that serves their area.
//注意ItemsControl的使用,在界面上的显示效果
这里用了一个Label(validationErrorReport)来显示验证错误信息,验证的错误是以Validation.Errors这个Attached Property作为载体。

 

通过Validation.ValidationAdornerSite和Validation.ValidationAdornerSiteFor可以设置错误消息源(ItemsControl中的各项)和接收错误的载体(Label)。

但是这种做法是有点问题的,我在中会讲这个例子的运行效果。其有问题的原因是因为Validation类是静态类,里面的所有成员及方法都是静态的,只能对一个有效。

Backend code:

public partial class Window1 : Window    {        Customers customerData;        BindingGroup bindingGroupInError = null;        public Window1()        {            InitializeComponent();            customerData = new Customers();
// 设置ItemsControl的源            customerList.DataContext = customerData;        }        void AddCustomer_Click(object sender, RoutedEventArgs e)        {            if (bindingGroupInError == null)            {                customerData.Add(new Customer());            }            else            {                MessageBox.Show("Please correct the data in error before adding a new customer.");            }        }        void saveCustomer_Click(object sender, RoutedEventArgs e)        {            Button btn = sender as Button;
// ItemsControl.ContainerFromElement MSND上是这么说的:返回属于拥有给定元素的当前  的容器。读起来和念易筋经一样             FrameworkElement container = (FrameworkElement) customerList.ContainerFromElement(btn);            // If the user is trying to change an items, when another item has an error,            // display a message and cancel the currently edited item.            if (bindingGroupInError != null && bindingGroupInError != container.BindingGroup)            {                MessageBox.Show("Please correct the data in error before changing another customer");                container.BindingGroup.CancelEdit();                return;            }            if (container.BindingGroup.ValidateWithoutUpdate())            {                container.BindingGroup.UpdateSources();                bindingGroupInError = null;                MessageBox.Show("Item Saved");            }            else            {                bindingGroupInError = container.BindingGroup;            }        }
 
ValicationRule文件:
public class Customers : ObservableCollection
{ public Customers() { Add(new Customer()); } } public enum Region { Africa, Antartica, Australia, Asia, Europe, NorthAmerica, SouthAmerica } public class Customer { public string Name { get; set; } public ServiceRep ServiceRepresentative { get; set; } public Region Location { get; set; } } public class ServiceRep { public string Name { get; set; } public Region Area { get; set; } public ServiceRep() { } public ServiceRep(string name, Region area) { Name = name; Area = area; } public override string ToString() { return Name + " - " + Area.ToString(); } } public class Representantives : ObservableCollection
{ public Representantives() { Add(new ServiceRep("Haluk Kocak", Region.Africa)); Add(new ServiceRep("Reed Koch", Region.Antartica)); Add(new ServiceRep("Christine Koch", Region.Asia)); Add(new ServiceRep("Alisa Lawyer", Region.Australia)); Add(new ServiceRep("Petr Lazecky", Region.Europe)); Add(new ServiceRep("Karina Leal", Region.NorthAmerica)); Add(new ServiceRep("Kelley LeBeau", Region.SouthAmerica)); Add(new ServiceRep("Yoichiro Okada", Region.Africa)); Add(new ServiceRep("T¨¹lin Oktay", Region.Antartica)); Add(new ServiceRep("Preeda Ola", Region.Asia)); Add(new ServiceRep("Carole Poland", Region.Australia)); Add(new ServiceRep("Idan Plonsky", Region.Europe)); Add(new ServiceRep("Josh Pollock", Region.NorthAmerica)); Add(new ServiceRep("Daphna Porath", Region.SouthAmerica)); } } // Check whether the customer and service representative are in the // same area. public class AreasMatch : ValidationRule { public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo) { BindingGroup bg = value as BindingGroup; Customer cust = bg.Items[0] as Customer; if (cust == null) { return new ValidationResult(false, "Customer is not the source object"); } Region region = (Region)bg.GetValue(cust, "Location"); ServiceRep rep = bg.GetValue(cust, "ServiceRepresentative") as ServiceRep; string customerName = bg.GetValue(cust, "Name") as string; // 相等说明验证通过
if (region == rep.Area)            {                return ValidationResult.ValidResult;            }            else            {                StringBuilder sb = new StringBuilder();                sb.AppendFormat("{0} must be assigned a sales representative that serves the {1} region. \n ", customerName, region);                return new ValidationResult(false, sb.ToString());            }        }    }

转载于:https://www.cnblogs.com/sjqq/p/7841292.html

你可能感兴趣的文章
【转】Java反射 之 反射基础
查看>>
mysql数据库备份和还原的常用命令
查看>>
s3c2440实验---定时器
查看>>
HBase配置性能调优(转)
查看>>
MyEclipse10安装SVN插件
查看>>
[转]: 视图和表的区别和联系
查看>>
Regular Experssion
查看>>
图论例题1——NOIP2015信息传递
查看>>
uCOS-II中的任务切换-图解多种任务调度时机与问题
查看>>
CocoaPods的安装和使用那些事(Xcode 7.2,iOS 9.2,Swift)
查看>>
Android 官方新手指导教程
查看>>
幸运转盘v1.0 【附视频】我的Android原创处女作,请支持!
查看>>
UseIIS
查看>>
数据库连接的三层架构
查看>>
集合体系
查看>>
vi命令提示:Terminal too wide
查看>>
引用 移植Linux到s3c2410上
查看>>
人与人之间的差距是从大学开始的
查看>>
MySQL5.7开多实例指导
查看>>
hdu 1029 Ignatius ans the Princess IV
查看>>