Question Are INotifyPropertyChanged and ValidationRule compatible?

mauede

Well-known member
Joined
Sep 1, 2021
Messages
103
Location
Northwood - UK
Programming Experience
Beginner
In my GUI I have a TextBox whose content can be edited at any time by the user and must be known in the code that has to use its latest value.
The TextBox is already bound to the procedure that checks its content is in the proper range:

C#:
  <Window.Resources>
        <local:DoubleRangeRule x:Key="DoubleRangeRule"/>
        <Style x:Key="textBoxInError" TargetType="{x:Type TextBox}">
            <Style.Triggers>
                <Trigger Property="Validation.HasError" Value="true">
                    <Setter Property="ToolTip"  Value="{Binding RelativeSource={x:Static RelativeSource.Self},  Path=(Validation.Errors)/ErrorContent}"/>
                </Trigger>
            </Style.Triggers>
        </Style>
        <ControlTemplate x:Key="validationTemplate">
            <DockPanel>
                <TextBlock Foreground="Red" FontSize="60">!</TextBlock>
                <AdornedElementPlaceholder/>
            </DockPanel>
        </ControlTemplate>
    </Window.Resources>



 <TextBox x:Name="DiceTol" Grid.Column="1" HorizontalAlignment="Left" Margin="655,0,0,0" Grid.Row="1"  VerticalAlignment="Bottom"
                          Validation.ErrorTemplate="{StaticResource validationTemplate}"   Style="{StaticResource textBoxInError}"  Background="Wheat"
                 FontFamily="Arial Black" FontWeight="Bold" FontSize="20" Width="100" Height="46" Grid.RowSpan="1"  >
            <TextBox.Text>
                <Binding Path="DiceThreshold" StringFormat="N2"  UpdateSourceTrigger="PropertyChanged">
                    <Binding.ValidationRules>
                        <local:DoubleRangeRule Min="0.0" Max="1.0"/>
                    </Binding.ValidationRules>
                </Binding>
            </TextBox.Text>
        </TextBox>


The code behind is :

C#:
   public class DoubleRangeRule : ValidationRule
    {
        public static readonly double DiceThresholdDefault = 0.33;

        public double Min { get; set; } = 0;

        public double Max { get; set; } = 1;

        public override ValidationResult Validate(object value, CultureInfo cultureInfo)
        {
            double parameter = 0;

            try
            {
                if (((string)value).Length > 0)
                {
                    parameter = Double.Parse((String)value);
                }
            }
            catch (Exception e)
            {
                MessageBox.Show($"Illegal characters or {e.Message}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return new ValidationResult(false, "");
            }

            if ((parameter < this.Min) || (parameter > this.Max))
            {
                MessageBox.Show($"Please enter value in the range: {this.Min} and { this.Max}", "Error", MessageBoxButton.OK, MessageBoxImage.Error);
                return new ValidationResult(false, "");
            }
            MainWindow.DiceThreshold = parameter;
            return new ValidationResult(true, null);
        }
    }


  public static double DiceThreshold { get; set; } = DoubleRangeRule.DiceThresholdDefault;

The above code makes a red arrow appear close to the TextBox when the user enters an unaccepted value. However, the TextBox content is not available to the code. I mean, the double variable "DiceThreshold" is used to initialize the TextBox but then it is not being updated when the user changes the TextBox content. Nevertheless, the TextBox content is being filtered by the data -validation mechanism..

I have already implemented INotiFyPropertyChanged for another GUI control:

C#:
 public class EditableStructures : INotifyPropertyChanged
        {
            public string StrName { get; set; }
            public bool IsAccepted { get; set; }
            public int NamInd { get; set; }
            private SpecialFeatures _specialFeatures;
            public SpecialFeatures SpecialFeatures
            {
                get { return _specialFeatures; }
                set
                {
                    _specialFeatures = value;
                    OnPropertyChanged("SpecialFeatures");
                }
            }
            public event PropertyChangedEventHandler PropertyChanged;

            protected void OnPropertyChanged(string name)
            {
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
            }
        }

Questions:
  • May I define the variable "DiceThreshold as a class
    C#:
    shown above that inherits from INotifyPropertyChanged instead of defining it as a simple field?
  • Will it clash with the Data-Validation procedure?
Thank you in advance
 
Just taking a quick look at your XAML, it doesn't look like you have two way binding setup. It looks like you only have one way from model to view. You also need the other direction from view to model.
 
Just taking a quick look at your XAML, it doesn't look like you have two way binding setup. It looks like you only have one way from model to view. You also need the other direction from view to model.
Yes. I tried adding "Mode=TwoWay" in the Binding Path. The compiler accepts but at runtime the data-validation procedure becomes ineffective. I can type in the TextBox-Text field whatever I want without any data validation reaction. That is why I was thinking of using INotiFyPropertyChanged for the C# variable "DiceThreshold" which should contain the current value of DiceTol.Text ("DiceTol" is the TextBox name).
Since the TextBox-Text is already bound to the procedure that does the data validation, my concern is about binding the same property (Text of the TextBox) also to the INotiftPropertyCHange procedure.
My concern stems from having tried to define another Binding in the XAML definition of the TextBox which is not accepted by the XAML parser.
 
Back
Top Bottom