-2

I have a WPF window with some ComboBox and TextBox controls in it. I populate the comboboxes upon initialization, and the textboxes have two-way bindings to some properties in my viewmodel.

I had this idea to randomize the selected indices of my comboboxes and the text in the text boxes in my window's code-behind upon clicking a button, just to see if my implementation and validation logic were sound, but using this method it's very tedious and error-prone to repeatedly set focus to each text box to trigger their validations. The textboxes hold values of double, so using UpdateSourceTrigger="PropertyChanged" doesn't allow manual input of the decimal symbol (point or comma or what have you) and I feel like both input methods should be supported.

Example xaml code:

<TextBox x:Name="DataValueBox" Grid.Row="3" Grid.Column="3" Height="auto" VerticalAlignment="Center" Margin="10 0">
    <TextBox.Text>
        <Binding ElementName="DataComboBox"
                 Path="SelectedItem.Value"
                 Mode="TwoWay"
                 ValidatesOnExceptions="True"
                 NotifyOnValidationError="True"
                 UpdateSourceTrigger="LostFocus">
            <Binding.ValidationRules>
                <validators:DoubleRule />
            </Binding.ValidationRules>
            <Binding.Converter>
                <converters:StringToDoubleConverter />
            </Binding.Converter>
        </Binding>
    </TextBox.Text>
</TextBox>

String to double converter (happens after validation):

public class StringToDoubleConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        => value.ToString();

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        => double.Parse(value.ToString(), NumberStyles.Float, CultureInfo.CurrentCulture);
}

String validation (checks if a string represents a double in the current culture):

public class DoubleRule : ValidationRule
{
    public override ValidationResult Validate(object value, CultureInfo cultureInfo)
    {
        string valueString = value.ToString();
        NumberStyles style = NumberStyles.Float;
        CultureInfo culture = CultureInfo.CurrentCulture;
        double _ = 0.0;

        // Initial parse attempt
        bool parsed = double.TryParse(valueString, style, culture, out _);
        return parsed ? ValidationResult.ValidResult : new ValidationResult(false, "Please input a valid decimal number.");
    }
}

Is there a way to trigger a textbox's validation sequence when I change its text from the code-behind, or is there a better way to provide randomized data that will trigger validations?

JansthcirlU
  • 688
  • 5
  • 21
  • In web development, this is typically done using a browser extension. You'll probably have to code something yourself, and raise events programmatically to trigger the validation sequence. Have you tried something like this? https://stackoverflow.com/questions/22718717/wpf-raise-programmatically-a-selectionchangedevent – Rudey Aug 14 '20 at 13:31
  • *Is there a way to trigger a textbox's validation sequence when I change its text from the code-behind?* Did you try to set the `Text` property? – mm8 Aug 14 '20 at 13:38
  • @Rudey my current code works in a similar way, but instead of raising an event, I just call each control's `Focus()` method. – JansthcirlU Aug 14 '20 at 13:39
  • @mm8 Yes, I do set the `Text` property in the code behind, but because I've set my validation to trigger upon losing focus, it does not validate when the text changes. I deliberately chose this trigger because otherwise my text boxes would not correctly allow manual data input. – JansthcirlU Aug 14 '20 at 13:40
  • How do you peform the validation? – mm8 Aug 14 '20 at 13:41
  • Using a custom `ValidationRule` in the textbox's binding. I'll update my question with that code, if that helps. – JansthcirlU Aug 14 '20 at 13:42
  • @mm8 I've updated my question with the validation and conversion code. – JansthcirlU Aug 14 '20 at 13:53
  • Your difficulties with validation are one of the reasons not to use validation rules in the UI and instead to validate in the viewmodel. In this instance though, are the users typing in numbers that must be a double? I would use a behavior and ensure they can only input valid numbers so invalid input is stopped at source. – Andy Aug 14 '20 at 14:24
  • Testing via the entire front end also seems a bit odd here. You have a component. The validation rule is a unit. Following basic unit testing process you should test it separately. Testing via ui is a bad idea. It'll be really slow and cumbersome. Your validation rule should be a thin wrapper around a piece of code which can be instantiated itself without any UI. You can then exercise tests on that specifically and discrete from everything else. – Andy Aug 14 '20 at 14:36
  • Hmm, I see. I find that quite hard to wrap my head around, mainly because I'm still very inexperienced with WPF. I'll have to read up on validations. As for now, this window isn't a very crucial part of the app so I guess I'll stick with my ugly solution for now. – JansthcirlU Aug 14 '20 at 14:44
  • Testing via the front end is unusual. Because it's really hard to do. Take a look at this behavior. https://stackoverflow.com/questions/16914224/wpf-textbox-to-enter-decimal-values – Andy Aug 14 '20 at 14:50

1 Answers1

1

Since you are setting the Text property of the TextBox elements in the code-behind already, you might as well update the source explicitly as well:

textBox.Text = "some random value...";
var be = textBox.GetBindingExpression(TextBox.TextProperty);
if (be != null)
    be.UpdateSource();

This will cause the validation rule(s) to fire.

mm8
  • 163,881
  • 10
  • 57
  • 88
  • Well, if there's a more elegant way to randomize data that can be randomized, that doesn't necessarily rely on writing everything out in the code-behind, that would also be great. The reason I'm doing it in code-behind is because I haven't figured out any alternative strategies. If I had a window with 20 comboboxes and 50 textboxes, I would probably start pulling my hair out. – JansthcirlU Aug 14 '20 at 14:01
  • I am not sure I understand your question then? The "real" way of doing validation would be to implement the `INotifyDataErrorInfo` interface in the view model instead of using validation rules in the view. But this is another story. – mm8 Aug 14 '20 at 14:03