Powered by MSDN

US - English
NEW! Silverlight 5 is available Learn More

DataGrid Validation when Save button is clicked RSS

6 replies

Last post Jul 14, 2010 03:34 AM by teyc

(0)
  • spatemp

    spatemp

    Member

    8 Points

    58 Posts

    DataGrid Validation when Save button is clicked

    Nov 19, 2009 09:22 PM | LINK

    I have a DataGrid on my page and the collection object that is bound to it has some validation on it.

    I was wandering if there is a way to fire validation on the grid when say Save button is clicked.  Meaning right before I push my data to database, I want to fire validation on grid to make sure that the grid or collection objects bound to it are in valid state.  If not, display a message to use and ask user to correct it. 

     Thanks.

  • esite

    esite

    Contributor

    3301 Points

    700 Posts

    Re: DataGrid Validation when Save button is clicked

    Nov 20, 2009 01:56 AM | LINK

    You can create a validate method on your business entity as in the snippet below and then itterate through your collection and validate each item. If you implemented the IEditableObject interface on your business object you can also extend that to mark a property as updated in order for you to use Linq to only return your dirty records, this way you can validate a smaller set.

    /// <summary>
            /// Validate this Object by calling the Validator
            /// </summary>
            /// <typeparam name="T"></typeparam>
            public virtual void Validate()
            {
                var validationContext = new ValidationContext(this, null, null);
                Validator.ValidateObject(this, validationContext);
            }
    
            #endregion Methods
    

     

     

    Anton Swanevelder Blog | LinkedIn | eSite
  • spatemp

    spatemp

    Member

    8 Points

    58 Posts

    Re: DataGrid Validation when Save button is clicked

    Nov 20, 2009 11:29 AM | LINK

    Thank esite you for your quick answer.   Could you please expand on this little. 

     "If you implemented the IEditableObject interface on your business object you can also extend that to mark a property as updated in order for you to use Linq to only return your dirty records, this way you can validate a smaller set."

     It would be nice if all invalid items would popup with error state (red) in the grid.  Also, after iterating through the collection and calling validate() method on each object, would you be able to inquire and say is there any invalid object in collection.   If so, display some error message to user and do not continue. 

    Thanks again.

  • Min-Hong Tang - MSFT

    Min-Hong Tan...

    All-Star

    28750 Points

    3295 Posts

    Re: DataGrid Validation when Save button is clicked

    Nov 23, 2009 08:03 AM | LINK

    Hi,

       Silverlight technology's validation system is very powerful.

       This is a very nice article, detailed and neat.

       http://blogs.msdn.com/nagasatish/archive/2009/03/22/datagrid-validation.aspx

    Best Regards

    Min-Hong Tang
    Microsoft Online Community Support

    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
  • spatemp

    spatemp

    Member

    8 Points

    58 Posts

    Re: DataGrid Validation when Save button is clicked

    Nov 23, 2009 11:16 AM | LINK

    MinHong,

     That is a very good article.  However, the solution in the article only validates.

    -          Once we modify the content of a particular cell (cell validation)
    -          Once we modify the content of a particular datagrid row (would like to commit changes to row) (Row Validation).  In this blog, I will try to give an intro both cell validation and row validation by using examples.

    What I need is when user clicks a Submit button to save data, I want to make sure all data in DataGrid is valid.   If not high light the cell with red error state.  And 1) I am wandering if this is possible.  2) Validator.ValidateObject only validates the validator attributes(Required, Range, etc...) on property.  But does not do anything, if I have validtion like below.

    By the way my DataGrid will be initially be loaded with some invalid data becuase thats how it exist in database plus an addition of new column this release that will be zero to begin with.  And so initially setter validation is turned off by a global flag(Global.IsValidate). 

            public new decimal RefurbPrice 
            { 
                get
                {
                    return refurbPrice;
                }
                set
                {
                    if (Global.IsValidate && (value < NewCost || value < 0))
                    {
                        throw new ValidationException("Refurb Price can not be greater then New Cost or Negative.");
                    }
                    refurbPrice = value;
                    RaisePropertyChanged("RefurbPrice");
                }
            }
    

     

     NewCost is a property on this object as well.

  • esite

    esite

    Contributor

    3301 Points

    700 Posts

    Re: DataGrid Validation when Save button is clicked

    Nov 23, 2009 01:30 PM | LINK

    Apologies for the late response.

    Unfortunately this is exactly where the Silverlight validation breaks down, something needs to change in order for the Validator to check the validation on the Setter of the property. Now on the BindingExpression exists a method called UpdateSource which forces validation on a control, in fact you can set in your binding to only check validation when you call this method by setting UpdateSourceTrigger=Explicit.

    I have been playing with this for a little while now, trying to get my facts right and I believe I am still not 100% there but this is what I have thus far:

    I created a BaseEntity class that contains a IsValid property and all my Entities inherits from this BaseEntity. I want to use IsValid to be able to later check if that Entity was in fact valid to be saved.

    Then I basically copied this class from another post http://forums.silverlight.net/forums/t/140537.aspx

     

    public static class DependencyObjectExtension
        {
            public static List GetChildObjects(this DependencyObject obj, string name)
            {
                var retVal = new List();
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    object c = VisualTreeHelper.GetChild(obj, i);
                    if (c.GetType().FullName == typeof(T).FullName && (String.IsNullOrEmpty(name) || ((FrameworkElement)c).Name == name))
                    {
                        retVal.Add((T)c);
                    }
                    var gc = ((DependencyObject)c).GetChildObjects(name);
                    if (gc != null)
                        retVal.AddRange(gc);
                }
    
                return retVal;
            }
    
            public static T GetChildObject(this DependencyObject obj, string name) where T : DependencyObject
            {
                for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
                {
                    object c = VisualTreeHelper.GetChild(obj, i);
                    if (c.GetType().FullName == typeof(T).FullName && (String.IsNullOrEmpty(name) || ((FrameworkElement)c).Name == name))
                    {
                        return (T)c;
                    }
                    object gc = ((DependencyObject)c).GetChildObject(name);
                    if (gc != null)
                        return (T)gc;
                }
    
                return null;
            }
    
        }

     

    You will need to create a class and copy the above in it, make sure your namespaces match, as this cool piece of code is an extender and extends the DependencyObject.

    In another Helper class I have a piece of code that uses the extension above to get controls on my page and then call the UpdateSource on each individually. My code look like this, but you will need to extend it for your purposes:

    public virtual void ValidateCollection(IEnumerable collection, DependencyObject dependencyObject)
            {
                //Reset the IsValid property before validation
                foreach (T entity in collection)
                {
                    (entity as BaseEntity).IsValid = true;
                }
    
                //TextBoxes
                var textBoxes = dependencyObject.GetChildObjects(null);
                foreach (var control in textBoxes)
                    UpdateSource(control, TextBox.TextProperty);
    
                //ComboBoxes
                var comboBoxes = dependencyObject.GetChildObjects(null);
                foreach (var control in comboBoxes)
                    UpdateSource(control, ComboBoxEdit.EditValueProperty);
    
            }
    
            private void UpdateSource(FrameworkElement control, DependencyProperty dp)
            {
                var binding = control.GetBindingExpression(dp);
                if (binding != null)
                    binding.UpdateSource();
            }

     

    From the example above you will see that I only cater for TextBoxes and ComboBoxEdit (devexpress).

    This is where you will need to jump in as I haven't done a Grid yet but I believe that might be able to pass a Grid.RowProperty here.

    The code I then call on my save looks like this:

    /// <summary>
            /// Save a Issue
            /// </summary>
            /// <param name="taskEntity"></param>
            public void Save(IProgress progressControl, FrameworkElement targetControl)
            {
                if (_IssueService != null)
                {
                    try
                    {
                        List dirtyCollection = GetDirtyRecords(Model).ToList();
                        //First Pass Validation
                        ValidateCollection(dirtyCollection, targetControl);
                        foreach (IssueEntity entity in dirtyCollection)
                        {
                            if (!((BaseEntity)entity).IsValid)
                                return;
                        }
                        //Second Pass Validation
                        ValidateCollection(dirtyCollection);
                        //Save Object
                        progressControl.StartSave(targetControl);
                        _IssueService.SaveIssue(dirtyCollection);
                    }
                    catch (ValidationException ex)
                    {
                        ShowValidationMessage(ex.Message);
                    }
                }
            }

     

    On your XAML page you will need to also register the BindingValidationError for LayoutRoot to do something like this:

    private void LayoutRoot_BindingValidationError(object sender, ValidationErrorEventArgs e)
            {
                if (e.OriginalSource is FrameworkElement)
                {
                    object dataContext = ((FrameworkElement)e.OriginalSource).DataContext;
                    if (dataContext is BaseEntity)
                        ((BaseEntity)dataContext).IsValid = false;
                }
            }
     

     

    It is still a bit ugly, trying to clean it up, but at least now when I click on Save, my validation errors are showing.

    You can also add a ValidationSummary control on your page that will show up when a Binding Error occured.

    HTH

    Anton Swanevelder Blog | LinkedIn | eSite
  • teyc

    teyc

    Contributor

    2427 Points

    615 Posts

    Re: DataGrid Validation when Save button is clicked

    Jul 14, 2010 03:34 AM | LINK

    Here's a possibly simpler method. You can loop through your entities and check them.


    Validate each entity:
    
     ValidationContext context =   
           new ValidationContext(person, null, null);  
      
           Validator.TryValidateObject(  
             person,  
             context,  
             person.ValidationErrors);  
      

    Alternately, you can try the technique here:

    http://devjitsu.com/blog/2010/06/03/entity-level-validation-with-ria-services

    http://devjitsu.com/blog/2010/06/03/entity-level-validation-with-ria-services


    (Mark as answered if this is what you're trying to achieve)