views:

4441

answers:

5

Hi,

I have been seriously disappointed with WPF validation system. Anyway! How can I validate the complete form by clicking the "button"?

For some reason everything in WPF is soo complicated! I can do the validation in 1 line of code in ASP.NET which requires like 10-20 lines of code in WPF!!

I can do this using my own ValidationEngine framework:

Customer customer = new Customer();
            customer.FirstName = "John";
            customer.LastName = String.Empty;

            ValidationEngine.Validate(customer);

            if (customer.BrokenRules.Count > 0)
            {
                // do something display the broken rules! 
            }
A: 

I would suggest to look at the IDataErrorInfo interface on your business object. Also have a look at this article: Self Validating Text Box

adriaanp
A: 

The description of your problem is a little vague to me. I mean, I'm not exactly sure what your difficulty is. Assuming that the DataContext is some sort of presenter or controller that has a propetry representing the customer instance, and ValidateCommand is a property of type ICommand:

  <StackPanel>  
    <TextBox Text="{Binding CurrentCustomer.FirstName}" />
    <TextBox Text="{Binding CurrentCustomer.LastName}" />
    <Button Content="Validate" 
            Command="{Binding ValidateCommand}"
            CommandParameter="{Binding CurrentCustomer}" />
    <ItemsControl ItemsSource="{Binding CurrentCustomer.BrokenRules}" />
  </StackPanel>

This XAML is really simplified, of course, and there are other ways to do it. As a Web developer who is now heavily involved with WPF, I find most tasks like this significantly easier in WPF.

bennage
+8  A: 

A WPF application should disable the button to submit a form iff the entered data is not valid. You can achieve this by implementing the IDataErrorInfo interface on your business object, using Bindings with ValidatesOnDataErrors=true. For customizing the look of individual controls in the case of errors, set a Validation.ErrorTemplate.

XAML:

<Window x:Class="Example.CustomerWindow" ...>
    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Save"
                        CanExecute="SaveCanExecute"
                        Executed="SaveExecuted" />
    </Window.CommandBindings>
    <StackPanel>
        <TextBox Text="{Binding FirstName, ValidatesOnDataErrors=true, UpdateSourceTrigger=PropertyChanged}" />
        <TextBox Text="{Binding LastName, ValidatesOnDataErrors=true, UpdateSourceTrigger=PropertyChanged}" />
        <Button Command="ApplicationCommands.Save" IsDefault="True">Save</Button>
        <TextBlock Text="{Binding Error}"/>
    </StackPanel>
</Window>

This creates a Window with two TextBoxes where you can edit the first and last name of a customer. The "Save" button is only enabled if no validation errors have occurred. The TextBlock beneath the button shows the current errors, so the user knows what's up.

The default ErrorTemplate is a thin red border around the erroneous Control. If that doesn't fit into you visual concept, look at Validation in Windows Presentation Foundation article on CodeProject for an in-depth look into what can be done about that.

To get the window to actually work, there has to be a bit infrastructure in the Window and the Customer.

Code Behind

// The CustomerWindow class receives the Customer to display
// and manages the Save command
public class CustomerWindow : Window
{
    private Customer CurrentCustomer;
    public CustomerWindow(Customer c) 
    {
        // store the customer for the bindings
        DataContext = CurrentCustomer = c;
        InitializeComponent();
    }

    private void SaveCanExecute(object sender, CanExecuteRoutedEventArgs e)
    {
        e.CanExecute = ValidationEngine.Validate(CurrentCustomer);
    }

    private void SaveExecuted(object sender, ExecutedRoutedEventArgs e) 
    {
        CurrentCustomer.Save();
    }
}

public class Customer : IDataErrorInfo, INotifyPropertyChanged
{
    // holds the actual value of FirstName
    private string FirstNameBackingStore;
    // the accessor for FirstName. Only accepts valid values.
    public string FirstName {
        get { return FirstNameBackingStore; }
        set {
            FirstNameBackingStore = value;
            ValidationEngine.Validate(this);
            OnPropertyChanged("FirstName");
        }
    }
    // similar for LastName        

    string IDataErrorInfo.Error {
        get { return String.Join("\n", BrokenRules.Values); }
    }

    string IDataErrorInfo.this[string columnName]
    {
        get { return BrokenRules[columnName]; }
    }
}

An obvious improvement would be to move the IDataErrorInfo implementation up the class hierarchy, since it only depends on the ValidationEngine, but not the business object.

While this is indeed more code than the simple example you provided, it also has quite a bit more of functionality than only checking for validity. This gives you fine grained, and automatically updated indications to the user about validation problems and automatically disables the "Save" button as long as the user tries to enter invalid data.

David Schmitt
This seems too much when all I need is to make sure all the fields are fill.
azamsharp
If you only need to make sure that all fields are filled, you can just put your validation codes into the Click handler of the submit button. But then your users will ask "Why can't I submit the form?" and you will still have to implement all the notification and stuff.
David Schmitt
It would be logical if all this would be part of the TextBox or input controls. Like <TextBox RequiredInput="true" ErrorMessage="Please fill in the fields" />
azamsharp
Validation rules are part of the data model, not the GUI. One has to be able to check validity of an object without GUI. For example, think about batch-oriented data processors.
David Schmitt
That is my point! Validation should be performed at GUI level and then at the domain level.
azamsharp
That is my point! WPF _can_ delegate Validation to the domain level by using binding and setting ValidatesOnDataErrors=true and/or ValidatesOnException=true. My answer shows one way to do that.
David Schmitt
A: 

I've done some web developing but mostly c# forms. I find WPF to be a bit cumbersome at times. It seams to be neither fish nor fowl. I find XAML to be very sloppy looking. Debugging leaves much to be desired though.

Ken
+1  A: 

You might be interested in the BookLibrary sample application of the WPF Application Framework (WAF). It shows how to use validation in WPF and how to control the Save button when validation errors exists.

jbe