Walter Fabio Simoni
Walter Fabio Simoni

Reputation: 5729

Launch ExceptionValidationRule from specific context

I have a class Client :

public class Client : INotifyPropertyChanged
{

    private string m_strCode;
    public string strCode
    {
        get { return m_strCode; }
        set
        {

            if (CodeIsValide(strCode))
            {                  
                m_strCode = value;
                FirePropertyChangedEvent("strCode");

            }
            else
            {
                throw new ApplicationException("bad Data !");
            }

            FirePropertyChangedEvent("strCode");

        }
    }

    private string m_strName;
    public string strName
    {
        get { return m_strName; }
        set
        {

            if (NameIsValide(strName))
            {
                m_strName = value;
                FirePropertyChangedEvent("strName");

            }
            else
            {
                throw new ApplicationException("Bad Data! ");
            }

            FirePropertyChangedEvent("strName");

        }
    }

    public Client(string Code, string Name)
    {
        strCode = Code;
        strName = Name;
    }

    public Client()
    {

    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void FirePropertyChangedEvent(string propertyName)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }

}

On my WPF Window, i have two textbox : on for client.strCode, and the other for client.strNom.

Here is the XAML :

<TextBox x:Name="TextBox_Code"
         HorizontalAlignment="Left"
         Height="25"
         Margin="106,230,0,0"
         TextWrapping="Wrap"
         VerticalAlignment="Top"
         Width="78">
  <TextBox.Text>
    <Binding Path="strCode"
             UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
        <ExceptionValidationRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

<TextBox x:Name="TextBox_Name"
         HorizontalAlignment="Left"
         Height="25"
         Margin="106,230,0,0"
         TextWrapping="Wrap"
         VerticalAlignment="Top"
         Width="78">
  <TextBox.Text>
    <Binding Path="strName"
             UpdateSourceTrigger="PropertyChanged">
      <Binding.ValidationRules>
        <ExceptionValidationRule />
      </Binding.ValidationRules>
    </Binding>
  </TextBox.Text>
</TextBox>

The data input are verifiyng with the ValidationProcess. If the validation is false, it appear a warning label near the textbox.

My problem is : If i load bad data ( from a DataBase) to a Collection of Client object. The load use the set() of my strCode and strName, and, if the data are bad, the ExceptionValidationRule cannot be throwing ( I think it's because the ExceptionValidationRule is not invoked from the textbox binded). ( I'm not English, it's not esay to explain sorry).

I think i need to specify when i want to invoke the verifiy process.

Anyone have advices please ?

If anyone want, i create a sample VS project in order to share my problem.

EDIT : If i use a Custom Validator class, it OK !

Just a question, in order to force the validation test, i need to do this, when i select the line in my DataGrid :

    private void myDataGrid_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
    {
        // Affiche le code évt sélectionné dans le tableau, dans les champs modifiable ( en haut de l'écran )

        var item = myDataGrid.SelectedItem as Client;
        if ((item != null))
        {
            TextBox_Code.Text = item.strCode;
            TextBox_Name.Text = item.strName;
        }
    }

:

TextBox_Code.Text = item.strCode;
TextBox_Name.Text = item.strName;

If i remove this two line, the textbox are corectly initialized because of the binding, but the validation process is not invoked. Why ? Is there a way to force the the validation process and use the full binding whitout :

TextBox_Code.Text = item.strCode;
TextBox_Name.Text = item.strName;

Thanks :)

Thanks a lot :)

Best regards,

Nixeus :)

Upvotes: 0

Views: 228

Answers (1)

Viv
Viv

Reputation: 17380

Well if I understand what your requiring correctly,

You do not want your exceptions raised if the property is set from anything apart from the xaml view.

My preferred solution would be to not use ExceptionValidationRule at all and prefer a Custom ValidationRule. This will solve your issue. Example shows how to create and use such a feature.

Example for a Custom Validation Rule:

public class CodeRangeRule : ValidationRule {
  public override ValidationResult Validate(object value, CultureInfo cultureInfo) {
    int strCode = -1;
    if (value != null && !Int32.TryParse(value.ToString(), out strCode))
      return new ValidationResult(false, "Illegal strCode");
    if (strCode < 9999 && strCode > 0) // Modify to suit your Validity Conditions
      return new ValidationResult(true, null);
    return new ValidationResult(false, "strCode is not within acceptable code range");
  }
}

and your xaml:

<TextBox x:Name="TextBox_Code" HorizontalAlignment="Left" Height="25" Margin="106,230,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="78">
    <TextBox.Text>
        <Binding Path="strCode"  UpdateSourceTrigger="PropertyChanged">
            <Binding.ValidationRules>
                <local:CodeRangeRule />
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

OR

If you do not want to use a Custom ValidationRule for whatever reason, you can keep your ExceptionValidationRule as it is in your view and either add a try catch before calling a setter from database load or in your

public class Client : INotifyPropertyChanged

add another property(say an enum with values kDatabaseLoad, kView) to indicate if the object is worked on by the View / Database. Thus in the setter of your strCode and strName check if this enum is kView before throwing your exception.

Now when you do a database load and create Client objects assign it's enum to kDatabaseLoad before setting strName and strCode. Make sure to switch the enum back to kView once done with the load.

Upvotes: 1

Related Questions