views:

238

answers:

3

Is there any way to force control validation in .NET CF? In full .NET there is the Validate() method, but it is missing from CF.

I'm trying to make a control bind data back to the model when closing the form, but clicking the main menu button doesn't seem to steal focus from the control and the Validating and Validated events don't fire.

Do you know of any workarounds for this problem?

+2  A: 

I struggled with very same issue about a year ago. Everything I found on the web was pretty nasty (i.e. iterate over controls and catch every control focus thus firing validate event or some solution that heavily relied on pinvoke or reflection - I don't exactly remember).

I ended up creating wrappers that included Validate method for my textboxes etc. and keeping collection of this wrappers. This way, I could iterate over my wrappers and call validate for every control.

That solution worked fine. First I tried the solution with programmatically catching every control focus but I had lots of problems with it. After wasting some time trying to improve this solution I decided to create these wrappers and this was very good decision.

UPDATE

Here how it looked like. Inform I declare list of controls that need to be validated:

private List<TextBoxWithValidation> textBoxesWithValidation;

In constructor I add controls to the list:

TextBoxWithValidation emailTextBoxWithValidation = new TextBoxWithValidation(emailTextBox);
emailTextBoxWithValidation.AddValidationPair(Validator.ValidationType.VALIDATE_NOT_EMPTY, "ValidateNotEmptyEmail");
emailTextBoxWithValidation.AddValidationPair(Validator.ValidationType.VALIDATE_EMAIL, "ValidateEmailEmail");
textBoxesWithValidation.Add(emailTextBoxWithValidation);

Then I am able to validate the form:

private bool ValidateForm()
{
  foreach (TextBoxWithValidation textBoxWithValidation in textBoxesWithValidation)
  {
    if (!textBoxWithValidation.Validate())
    {
      return false;
    }
  }
  return true;
}

And textbox with validation looks like this:

class TextBoxWithValidation
{
  class ValidationTypeMessagePair
  {
    public Validator.ValidationType ValidationType { get; set; }
    public string ValidationMessage { get; set; }

    public ValidationTypeMessagePair(Validator.ValidationType validationType, string validationMessage)
    {
      this.ValidationType = validationType;
      this.ValidationMessage = validationMessage;
    }
  }

  private List<ValidationTypeMessagePair> validationPairs;
  private TextBox textBox;

  public TextBoxWithValidation(TextBox textBox)
  {
    this.textBox = textBox;
    this.textBox.DataBindings["Text"].DataSourceUpdateMode = DataSourceUpdateMode.Never;      
    validationPairs = new List<ValidationTypeMessagePair>();
  }

  public void AddValidationPair(Validator.ValidationType validationType, string validationMessage)
  {
    validationPairs.Add(new ValidationTypeMessagePair(validationType, validationMessage));
  }

  public bool Validate()
  {
    foreach (ValidationTypeMessagePair validationPair in validationPairs)
    {
      if (!Validator.Validate(validationPair.ValidationType, textBox, Messages.Localize(validationPair.ValidationMessage))) return false;
    }
    textBox.DataBindings["Text"].WriteValue();
    return true;
  }

  public void ClearValidationStatus()
  {
    textBox.BackColor = System.Drawing.SystemColors.Window;
  }

}
empi
Interesting approach - how exactly did you implement these Validate methods in the wrappers? I'm actually having this issue with a third party control (Resco DetailView) and am wondering whether it would be possible to apply the same technique. Did you inherit from these controls? Did you manage to keep the design-time support?
Michał Drozdowicz
Thanks for the code - haven't seen DataBindings[string].WriteValue before. As per my answer I didn't need to follow your approach, but if I ever need to force binding the data back, your answer would be very helpful.
Michał Drozdowicz
A: 

In case anyone finds it useful, I'll describe the workaround I've applied.

In the OK handler I've added code that Focuses on the Panel that contains the control I want to validate. When the data edit control loses focus it fires the Validating and Validated events and binds the data back to the model class. This way, the form (which btw is generic for many parts of the 'wizard' and knows only of the Panel onto which the screens are loaded) can force validating the control.

A bit of a hack, but it will do for now.

Michał Drozdowicz
Updated my answer with code sample. As I said before, I tried using focus event to validate the form. However, I had no luck with it. The fact that there is no easy way to validate a form in compact framework is pretty weird.
empi
A: 

I think, in order to trigger the Validating and Validated events through focusing on other control, you need to set the Form AutoValidate property to AutoValidate.EnableAllowFocusChange.

Hope it helps. =]

Zero