Thanks to Michael for his help. Unfortunately, I need bindings so that they remain constantly synchronized, and only the check is delayed. Otherwise, Michael's decision will do the job. So, I went in a slightly different direction. Here is the solution that I ultimately implemented.
Simple demo:. Start with the simplest case: my business objects implement IDataErrorInfo ; Let's say I can change the way it is implemented. I give each business object an additional logical property, ValidationEnabled , and I modify the implementation of IDataErrorInfo to always return a null result if this property is false.
The demo that I mentioned in my original post uses a Contact object with two properties; Name and surname. I added the ValidationEnabled property and changed the IDataErrorInfo implementation, as shown below:
#region IDataErrorInfo Members public string Error { get { throw new System.NotImplementedException(); } } public string this[string columnName] { get { // Initialize string result = null; // Perform validation only if enabled if (ValidationEnabled) { switch (columnName) { // Validate 'First Name' case "FirstName": if (string.IsNullOrEmpty(FirstName)) { result = "First name has to be set"; } else if(FirstName.Length < 5) { result = "First name must be at least five characters"; } break; // Validate "Last Name" case "LastName": if (string.IsNullOrEmpty(LastName)) { result = "Last name has to be set"; } else if (LastName.Length < 5) { result = "Last name must be at least five characters"; } break; } } // Set return value return result; } }
In my version of a simple demo, I connect the submit button to an event handler in code that allows you to check and update bindings for both text fields:
private void OnButtonClick(object sender, RoutedEventArgs e) { var contact = (Contact) DataContext; contact.ValidationEnabled = true; var binding = FirstNameBox.GetBindingExpression(TextBox.TextProperty); binding.UpdateSource(); binding = LastNameBox.GetBindingExpression(TextBox.TextProperty); binding.UpdateSource(); }
Now the red outlines do not appear until I try to submit the form.
Real world: In my working application, I do not control business objects, and I cannot modify them, as it was in my simple demonstration. Thus, I create a simple end-to-end wrapper for a business object that provides properties for attaching data to a view and associates these properties with the corresponding properties of the wrapped business object. The wrapper implements IDataErrorInfo and contains the ValidationEnabled property.
An IDataErrorInfo shell implementation always returns null if validation is not enabled. If validation is enabled, then the shell calls the implementation of IDataErrorInfo on the wrapped object and returns what it receives from there.
This approach will be familiar to anyone using the Model-View-ViewModel template. What we do is create a wrapper for the presentation model for the business object, which is considered the best MVVM practice for many developers. It separates the user interface problem (suppressing the red borders before the page is sent) for business model reasons (simple object validation).
In addition, my production application will not use encoded event handlers. On MVVM, the button will be connected to ICommand, which will contain the logic from the OnButtonClick () handler in a simple demo.
I hope this helps anyone who tackles this issue in the future.