A little late, but figured this was a little more dynamic.
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
public static class ValidationUtility
{
public static void Validate(object entity, UIElement element)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
var child = (UIElement)VisualTreeHelper.GetChild(element, i);
Validate(entity, child);
}
if (element is FrameworkElement)
{
IEnumerable <bindingExpressions> = from f in element.GetType().GetFields(BindingFlags.Static | BindingFlags.Public)
where f.FieldType == typeof(DependencyProperty)
let be = ((FrameworkElement)element).GetBindingExpression ((DependencyProperty)f.GetValue(element))
where be != null && be.ParentBinding != null && be.ParentBinding.ValidatesOnExceptions && be.DataItem == entity
select be;
foreach (BindingExpression bindingExpression in bindingExpressions)
{
bindingExpression.UpdateSource();
}
}
}
}
Cheers to ryanhaney for a sweet piece of LINQ code. For those needing a VB translation, try this.
Note: This website doesn't like "GetBindingExpression"--so I've added a space below.
Imports System.Linq
Imports System.Reflection
Imports System.Windows.Data
Public Module ValidationUtility
Public Sub Validate(ByVal entity As Object, ByVal element As UIElement)
For i As Integer = 0 To VisualTreeHelper.GetChildrenCount(element) - 1
Dim child = DirectCast(VisualTreeHelper.GetChild(element, i), UIElement)
Validate(entity, child)
Next
If TypeOf element Is FrameworkElement Then
Dim bindingExpressions = _
From bx In _
(From fd In element.GetType().GetFields(BindingFlags.Static Or BindingFlags.Public) _
Where fd.FieldType Is GetType(DependencyProperty) _
Select CType(element, FrameworkElement).GetBindingExpressio n(CType(fd.GetValue(element), DependencyProperty))) _
Where bx IsNot Nothing _
AndAlso bx.ParentBinding IsNot Nothing _
AndAlso bx.ParentBinding.ValidatesOnExceptions _
AndAlso Equals(bx.DataItem, entity) _
Select bx
For Each bindingExpression As BindingExpression In bindingExpressions
bindingExpression.UpdateSource()
Next
End If
End Sub
End Module
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
var child = (UIElement)VisualTreeHelper.GetChild(element, i);
ForceValidate(child);
}
if (element is FrameworkElement && element.Visibility == Visibility.Visible)
{
var type = element.GetType();
while (type != typeof(UIElement))
{
var bindingExpressions = from f in type.GetFields(BindingFlags.Static | BindingFlags.Public)
where f.FieldType == typeof(DependencyProperty)
let be = ((FrameworkElement)element).GetBindingExpression((DependencyProperty)f.GetValue(element))
where be != null && be.ParentBinding != null && be.ParentBinding.ValidatesOnExceptions && be.DataItem == this
select be;
foreach (BindingExpression bindingExpression in bindingExpressions)
{
bindingExpression.UpdateSource();
}
type = type.BaseType;
}
}
}
Here's a bit of tweak to the linq solution. This will also pick up any bindings that are set using DependencyPropertys from a base class (ie SelectedItem for a dropdown).
public void ForceValidate(UIElement element)
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++)
{
var child = (UIElement)VisualTreeHelper.GetChild(element, i);
ForceValidate(child);
}
if (element is FrameworkElement && element.Visibility == Visibility.Visible)
{
var type = element.GetType();
while (type != typeof(UIElement))
{
var bindingExpressions = from f in type.GetFields(BindingFlags.Static | BindingFlags.Public)
where f.FieldType == typeof(DependencyProperty)
let be = ((FrameworkElement)element).GetBindingExpression((DependencyProperty)f.GetValue(element))
where be != null && be.ParentBinding != null && be.ParentBinding.ValidatesOnExceptions && be.DataItem == this
select be;
foreach (BindingExpression bindingExpression in bindingExpressions)
{
bindingExpression.UpdateSource();
}
type = type.BaseType;
}
}
}
I personnaly use this solution : http://blog.lexique-du-net.com/index.php?post/2010/10/19/RIA-Services-Force-validation-on-my-entities-%28and-just-the-validation-%21%29
++
Jonathan ANTOINE
MVP - Client Application Development
http://blog.lexique-du-net.com
http://wpf-france.fr
I am getting problem with Entity.HasValidationErrors flag. Custom Validation doesn't remove Errors from Entity. I am using ForceValidation method to validate my controls.
Error raised by custom validator doesn't get removed from entity after fixing form values.
I debugged custom validator on client side it doesn't raise any error once form value is fixed.
public static void ForceValidation(IEnumerable uiElements)
{
foreach (var uiElement in uiElements)
{
BindingExpression bindingExpression = null;
switch (uiElement.GetType().ToString())
{
case "System.Windows.Controls.StackPanel":
case "System.Windows.Controls.Panel":
ForceValidation(((Panel)uiElement).Children);
break;
case "System.Windows.Controls.TextBox":
bindingExpression = ((TextBox)uiElement).GetBindingExpression(TextBox.TextProperty);
break;
case "System.Windows.Controls":
bindingExpression = ((TextBox)uiElement).GetBindingExpression(TextBox.TextProperty);
break;
case "System.Windows.Controls.RadioButton":
bindingExpression = ((RadioButton)uiElement).GetBindingExpression(ToggleButton.IsCheckedProperty);
break;
case "Telerik.Windows.Controls.RadDatePicker":
bindingExpression = ((RadDatePicker)uiElement).GetBindingExpression(RadDatePicker.SelectedValueProperty);
break;
case "Telerik.Windows.Controls.RadMaskedTextBox":
bindingExpression = ((RadMaskedTextBox)uiElement).GetBindingExpression(RadMaskedTextBox.ValueProperty);
break;
}
if (bindingExpression == null || bindingExpression.ParentBinding == null) continue;
if (!bindingExpression.ParentBinding.ValidatesOnExceptions) continue;
bindingExpression.UpdateSource();
}
}
public class CustomValidation
{
public static ValidationResult BizNo(string str)
{
// Perform validation logic here and set isValid to true or false.
if(str.Equals("0000"))
{
return new ValidationResult("Please enter valid biz no");
}
else
{
return ValidationResult.Success;
}
}
}
//This is how I am doing binding
b = new Binding("ORequest.Customer_BIS_Number");
b.Source = _oViewModel;
b.Mode = BindingMode.TwoWay;
b.NotifyOnValidationError = true;
b.ValidatesOnExceptions = true;
txtCusBizNo.SetBinding(TextBox.TextProperty, b);
//This is how RIA service code generated looks at client side [CustomValidation(typeof(Bnz.Bi.DailySalesAndReferrals.Web.Shared.CustomValidation), "BizNo")]
[DataMember()]
[Required(ErrorMessage="Customer BIS Number is required.")]
[StringLength(100)]
public string Customer_BIS_Number
{
get
{
return this._customer_BIS_Number;
}
set
{
if ((this._customer_BIS_Number != value))
{
this.OnCustomer_BIS_NumberChanging(value);
this.RaiseDataMemberChanging("Customer_BIS_Number");
this.ValidateProperty("Customer_BIS_Number", value);
this._customer_BIS_Number = value;
this.RaiseDataMemberChanged("Customer_BIS_Number");
this.OnCustomer_BIS_NumberChanged();
}
}
}
OnSave(){
//This is how I call forcevalidation on My Silverlight ViewPage
Helpers.Helper.ForceValidation(this.LayoutRoot.Children);
//This flag is always true once custom validator finds any error
//even after correcting form values
ViewModel.MyEntity.HasValidationErrors; }
I'm guesssing you could just clear ALL the errors and then run the validator again. (I don't use the Entity stuff so I'm not sure how you accomplish that)
I haven't looked at this stuff for quite a while, but my recollection was that the tab controls don't show up until they are actually visible and I had to programmatically select each tab, iterate for errors, then reselect original tab.
It MIGHT have been I had to do that so that the ValidationSummary actually had objects associated with the lines in the Summary.
OR
Maybe I had to iterate those to FIND the object in error. So that when they clicked on the validation error it could locate the object in error for the user to see. Otherwise, if the control in error was visible, clicking found and highlighted it and if
it wasn't visible, it did nothing which would be confusing for the user.
ryanhaney
Member
2 Points
1 Post
Re: How to manually validate an object and have the results automatically added to a ValidationSu...
Dec 20, 2009 11:20 AM | LINK
A little late, but figured this was a little more dynamic.
billvo
Member
6 Points
4 Posts
Re: Re: How to manually validate an object and have the results automatically added to a Validati...
Jan 15, 2010 08:19 PM | LINK
Cheers to ryanhaney for a sweet piece of LINQ code. For those needing a VB translation, try this. Note: This website doesn't like "GetBindingExpression"--so I've added a space below.
vinco
Member
4 Points
2 Posts
Re: How to manually validate an object and have the results automatically added to a ValidationSu...
Jan 22, 2010 08:10 PM | LINK
One more fix, ensures that all controls are already loaded.
Kellen
Member
6 Points
12 Posts
Re: How to manually validate an object and have the results automatically added to a ValidationSu...
Jul 22, 2010 06:40 PM | LINK
Here's a bit of tweak to the linq solution. This will also pick up any bindings that are set using DependencyPropertys from a base class (ie SelectedItem for a dropdown).
public void ForceValidate(UIElement element) { for (int i = 0; i < VisualTreeHelper.GetChildrenCount(element); i++) { var child = (UIElement)VisualTreeHelper.GetChild(element, i); ForceValidate(child); } if (element is FrameworkElement && element.Visibility == Visibility.Visible) { var type = element.GetType(); while (type != typeof(UIElement)) { var bindingExpressions = from f in type.GetFields(BindingFlags.Static | BindingFlags.Public) where f.FieldType == typeof(DependencyProperty) let be = ((FrameworkElement)element).GetBindingExpression((DependencyProperty)f.GetValue(element)) where be != null && be.ParentBinding != null && be.ParentBinding.ValidatesOnExceptions && be.DataItem == this select be; foreach (BindingExpression bindingExpression in bindingExpressions) { bindingExpression.UpdateSource(); } type = type.BaseType; } } }jmix90
Member
12 Points
8 Posts
Re: How to manually validate an object and have the results automatically added to a ValidationSu...
Oct 25, 2010 08:43 AM | LINK
Hello,
I personnaly use this solution : http://blog.lexique-du-net.com/index.php?post/2010/10/19/RIA-Services-Force-validation-on-my-entities-%28and-just-the-validation-%21%29
++
MVP - Client Application Development
http://blog.lexique-du-net.com
http://wpf-france.fr
sunil_ssb
Member
4 Points
3 Posts
Re: How to manually validate an object and have the results automatically added to a ValidationSu...
May 22, 2012 09:40 PM | LINK
I am getting problem with Entity.HasValidationErrors flag. Custom Validation doesn't remove Errors from Entity. I am using ForceValidation method to validate my controls.
Error raised by custom validator doesn't get removed from entity after fixing form values.
I debugged custom validator on client side it doesn't raise any error once form value is fixed.
public static void ForceValidation(IEnumerable uiElements)
{
foreach (var uiElement in uiElements)
{
BindingExpression bindingExpression = null;
switch (uiElement.GetType().ToString())
{
case "System.Windows.Controls.StackPanel":
case "System.Windows.Controls.Panel":
ForceValidation(((Panel)uiElement).Children);
break;
case "System.Windows.Controls.TextBox":
bindingExpression = ((TextBox)uiElement).GetBindingExpression(TextBox.TextProperty);
break;
case "System.Windows.Controls":
bindingExpression = ((TextBox)uiElement).GetBindingExpression(TextBox.TextProperty);
break;
case "System.Windows.Controls.RadioButton":
bindingExpression = ((RadioButton)uiElement).GetBindingExpression(ToggleButton.IsCheckedProperty);
break;
case "Telerik.Windows.Controls.RadDatePicker":
bindingExpression = ((RadDatePicker)uiElement).GetBindingExpression(RadDatePicker.SelectedValueProperty);
break;
case "Telerik.Windows.Controls.RadMaskedTextBox":
bindingExpression = ((RadMaskedTextBox)uiElement).GetBindingExpression(RadMaskedTextBox.ValueProperty);
break;
}
if (bindingExpression == null || bindingExpression.ParentBinding == null) continue;
if (!bindingExpression.ParentBinding.ValidatesOnExceptions) continue;
bindingExpression.UpdateSource();
}
}
public class CustomValidation
{
public static ValidationResult BizNo(string str)
{
// Perform validation logic here and set isValid to true or false.
if(str.Equals("0000"))
{
return new ValidationResult("Please enter valid biz no");
}
else
{
return ValidationResult.Success;
}
}
}
//This is how I am doing binding
b = new Binding("ORequest.Customer_BIS_Number");
b.Source = _oViewModel;
b.Mode = BindingMode.TwoWay;
b.NotifyOnValidationError = true;
b.ValidatesOnExceptions = true;
txtCusBizNo.SetBinding(TextBox.TextProperty, b);
//This is how RIA service code generated looks at client side [CustomValidation(typeof(Bnz.Bi.DailySalesAndReferrals.Web.Shared.CustomValidation), "BizNo")]
[DataMember()]
[Required(ErrorMessage="Customer BIS Number is required.")]
[StringLength(100)]
public string Customer_BIS_Number
{
get
{
return this._customer_BIS_Number;
}
set
{
if ((this._customer_BIS_Number != value))
{
this.OnCustomer_BIS_NumberChanging(value);
this.RaiseDataMemberChanging("Customer_BIS_Number");
this.ValidateProperty("Customer_BIS_Number", value);
this._customer_BIS_Number = value;
this.RaiseDataMemberChanged("Customer_BIS_Number");
this.OnCustomer_BIS_NumberChanged();
}
}
}
OnSave(){
//This is how I call forcevalidation on My Silverlight ViewPage
Helpers.Helper.ForceValidation(this.LayoutRoot.Children);
//This flag is always true once custom validator finds any error
//even after correcting form values
ViewModel.MyEntity.HasValidationErrors; }
mtiede@swtec...
Contributor
5366 Points
2236 Posts
Re: How to manually validate an object and have the results automatically added to a ValidationSu...
May 23, 2012 12:43 PM | LINK
I'm guesssing you could just clear ALL the errors and then run the validator again. (I don't use the Entity stuff so I'm not sure how you accomplish that)
I haven't looked at this stuff for quite a while, but my recollection was that the tab controls don't show up until they are actually visible and I had to programmatically select each tab, iterate for errors, then reselect original tab.
It MIGHT have been I had to do that so that the ValidationSummary actually had objects associated with the lines in the Summary.
OR
Maybe I had to iterate those to FIND the object in error. So that when they clicked on the validation error it could locate the object in error for the user to see. Otherwise, if the control in error was visible, clicking found and highlighted it and if it wasn't visible, it did nothing which would be confusing for the user.