James Joshua Street
James Joshua Street

Reputation: 3409

WPF How to use a validation rule in a textbox without creating an extra property to bind to in dialogbox?

so I have one example that is working here:

     <TextBox.Style>
          <Style TargetType="{x:Type TextBox}">
            <Style.Triggers>
              <Trigger Property="Validation.HasError" Value="true">
                <Setter Property="ToolTip"
                          Value="{Binding RelativeSource={RelativeSource Self}, 
                        Path=(Validation.Errors), Converter={StaticResource ValidationConverter}}"
                        />
              </Trigger>
              <Trigger Property="Validation.HasError" Value="false">
                <Setter Property="ToolTip"
                          Value="GraphPenWidth" />
                <Setter Property="Background" 
                    Value="Blue"
                    />
              </Trigger>
            </Style.Triggers>
          </Style>
        </TextBox.Style>
        <TextBox.Text>
          <Binding Path="GraphPenWidth" UpdateSourceTrigger="PropertyChanged"  Mode="TwoWay">
            <Binding.ValidationRules>
              <DaedalusValidationRules:IntegerValidationRule />
            </Binding.ValidationRules>
          </Binding>
        </TextBox.Text>

However, is there any way to use a validation rule without binding to a datacontext?

I am trying to make a generic dialogbox that I can pass various validation rules to. However, I found after a while that even when I create the validation rule in xaml it wasn't working correctly. I had read that I could just bind the TextBox's Text Property to itself, but this did not work.

However, when I put a breakpoint in the ValidationRule it seems to be getting called at the correct point when I insert data. In addition the style appears to be working because the background is blue. That leads me to believe that Validation.HasError is never becoming true or is becoming true and changing back so fast that I can't see the change.

The validation rule gets called after every letter I type, yet the textbox doesn't update to show haserror = true. why is this?

Am I just not allowed to bind a property to itself? is there any other way I can use a validation rule without having a binding or do I just always have to create an extra property to bind to? The shortest fix is just to create an extra text property and bind it pointlessly, but I had hoped that wasn't necessary.

 <TextBox    
    Margin="3"
    Height="25"
    VerticalAlignment="Center"
    VerticalContentAlignment="Center"
    HorizontalContentAlignment="Left"
    Grid.Column="1"
    x:Name="MainTextBox"
    >
    <TextBox.Text>
      <Binding RelativeSource="{RelativeSource Self}" Path="Text" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <rules:IntegerValidationRule />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>

    <TextBox.Style>
      <Style 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), Converter={StaticResource ValidationConverter}}"
                    />
            <Setter Property="Background" 
                    Value="Red"
                    />
          </Trigger>
          <Trigger Property="Validation.HasError" Value="false">
            <Setter Property="ToolTip"
                          Value="Default Signal Height Percentage" />
            <Setter Property="Background" 
                    Value="Blue"
                    />
          </Trigger>
        </Style.Triggers>
      </Style>
    </TextBox.Style>
  </TextBox>

So I actually managed to get the validation working in xaml by just making a property to bind against called Text on the GenericDialogBox and then binding that Text property to the Text Property of the Textbox. However, I can't seem to get the same code to work in the code behind.

  <TextBox.Text>
      <Binding Path="Text" UpdateSourceTrigger="PropertyChanged">
        <Binding.ValidationRules>
          <rules:IntegerValidationRule />
        </Binding.ValidationRules>
      </Binding>
    </TextBox.Text>

but when i try this in the code behind, it doesn't work.

  Binding myBinding = new Binding();
  myBinding.Source = this;
  myBinding.Path = new PropertyPath("Text");
  myBinding.NotifyOnValidationError = true;
  myBinding.NotifyOnSourceUpdated = true;

  myBinding.UpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged;

  myBinding.ValidationRules.Add(rule);
  MainTextBox.SetBinding(TextBlock.TextProperty, myBinding);

what am I missing?

Upvotes: 5

Views: 10765

Answers (2)

James Joshua Street
James Joshua Street

Reputation: 3409

Gave up on binding from code behind, i create a binding to a property in the xaml, and then in the constructor's code behind, I take the validation rule passed to the constructor and add it to the validation rules like so:

public GenericDialogBox(string MainLabelContent, string WindowTitle, string TextboxDefaultText, ValidationRule rule)
    {
      this.DataContext = this;
      Text = "";
      if (rule != null)
      {
        TextBoxValidationRule = rule;
      }
      InitializeComponent();
      MainLabel.Content = MainLabelContent;
      Title = WindowTitle;

      Binding binding = BindingOperations.GetBinding(MainTextBox, TextBox.TextProperty);
      binding.ValidationRules.Add(rule);


      MainTextBox.SelectAll();
      MainTextBox.Focus();
    }

Upvotes: 1

Anatoliy Nikolaev
Anatoliy Nikolaev

Reputation: 22702

Try set for your Binding NotifyOnValidationError to True, by default it is False:

Gets or sets a value that indicates whether the BindingValidationError event is raised on validation errors.

Example:

<Binding NotifyOnValidationError="True" UpdateSourceTrigger="PropertyChanged" ... />

Also you can see the ValidatesOnDataErrors property, he is used when your ViewModel implement the IDataErrorInfo interface.

Upvotes: 4

Related Questions