Here's the scenario. I have a textbox on the UI which is bound to a double property. If a character, say a '#' is typed in the textbox, the WPF validation is not enough for the application. I need to display a custom message and also disable some controls from the code. (These controls to be disabled are not part of the xaml.) As of now, the only way I could think of to do this is to bind the textbox to a string property and use the TryParse method. However, this will be a huge inconvenience. Is there a way to get the notification that an invalid character has been entered, without having to change the property to the string type?
well i use the "string" solution in my viewmodel. works best with IDataErrorInfo and binding.
but sometimes i also use a InputMaskbehavior for my Textboxe. so the user can just input characters wich is defined for the inputmask.
If you are using the MVVM pattern then you probably should have a string property in your ViewModel as this is what is entered on a Textbox. Even when you need the double for your model you have a string on your view. Then you can do whatever validation you need on the string property. Something like:
public string TextProperty
{
get
{
return _textProperty;
}
set
{
if (_textProperty != value)
{
_doubleProperty = this.TransformAndValidateString(value);
_textProperty = value;
}
}
}
Regarding disabling controls when an error is present look here:
IDataErrorInfo
Related
I have read about customising input validation for ASP.NET requests to avoid the dreaded "a potentially dangerous value was detected". I'm using the following code to allow angled brackets to pass validation.
public class RequestValidator : System.Web.Util.RequestValidator {
protected override bool IsValidRequestString(HttpContext context, string value, RequestValidationSource requestValidationSource, string collectionKey, out int validationFailureIndex) {
validationFailureIndex = 0;
switch (requestValidationSource) {
case RequestValidationSource.Form:
if (control is CustomTextBox) { // How can I get the control?
// allow angle brackets to pass validation
value = value.Replace("<", "<").Replace(">", ">");
}
break;
}
return base.IsValidRequestString(context, value, requestValidationSource, collectionKey, out validationFailureIndex);
}
}
Now that I'm allowing these potentially dangerous values through the validation filter I'd like to be sure that they're being properly handled. This is a Web Forms environment so I thought I'd create a CustomTextBox control, override the Text property and HtmlEncode the string.
As you can see from the comment in the code above, I'd like to restrict my RequestValidator so that it only allows 'dangerous' values to pass validation if I can be sure they're going to be handled by my CustomTextBox. How can I get a reference to the Control when all we have to go on is the value and the collectionKey?
The validation of the Form Keys happen even before the Page PreInit event. There are no controls created at that time.
I think your best chance would be holding to a collection of UniqueIDs of all CustomTextBox instances that exists on the page currently. Having that collection, you could check if the form key being validated exists on the collection, meaning that it is in fact a CustomTextBox.
This collection could be managed inside the CustomTextBox control and saved on the Session or Application Cache.
I would suggest to explicitly set ValidateRequestMode property to ValidateRequestMode.Disabled in your custom control constructor and override Text property (or whatever property or you are using to store value) getter and there return sanitized value based on your specific scenario.
I have a text bound to a property as follows
The user is expected to type in a File Name. Sometimes however users may type in invalid characters. So my backing property in the View Model looks as shown below
private string outputFileName;
public string OutputFileName
{
get
{
return outputFileName;
}
set
{
string temp = value;
if (true == IsValidFileName(temp))// this function uses Path.Getinvalidfilechars
{
outputFileName = value;
}
else
{
MessageBox.Show(string.Format("{0} contains one or more invalid characters
for a file Name",temp));
}
base.OnPropertyChanged("OutputFileName");
}
}
Here is the problem, the text box still shows the invalid char. why is the OnPropertyChanged not causing the text in the text box to go back to the old value without the invalid char.
How can I get that behaviour
In the else statement, the backing field for OutputFileName is not being assigned a different value. If you want to revert back to the previous value, then save that in another variable and update the backing field in the else statement and then the property changed event will change the UI with the old value. Although, I don't think this is very good user experience.
A better solution would to be use some validators and inform the user that the input needs to be corrected, rather than just reverting the value back to the previous value.
Google up "wpf validation" or start with this SO question: WPF Data Binding and Validation Rules Best Practices
What is the base class of your class that defines the OutputFileName? That class' OnPropertyChange method seems to check if the property value really changed before firing the PropertyChanged event. I tried your example with a class that directly implements INotifyPropertyChanged and does
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("OutputFileName"));
}
and that works as you expect. Although i agree with Marc, showing a MessageBox from a property setter is rather uncommon.
I am looking for a simple solution to the following problem:
I am using a simple TextBox control with the Text property bound to a property in the code behind. Additionally I am using a validation rule to notify the user of malformed input.
... error display style here ...
Now after entering valid data into the TextBox the user can hit a button to send the data. When clicking the button the data from the bound property UserName in the code behind is evaluated and sent.
The problem is that a user can enter valid data into the TextBox and this will be set in the property UserName. If the user then decides to change the text in the TextBox and the data becomes invalid, the setter of the property UserName is not called after the failed validation.
This means that the last valid data remains in the property UserName, while the TextBox display the invalid data with the error indicator. If the user then clicks on the button to send the data, the last valid data will be sent instead of the current TextBox content.
I know I could deactivate the button if the data is invalid and in fact I do, but the method is called in the setter of UserName. And if that is not called after a failed validation the button stays enabled.
So the question is: How do I enable calling of the property setter after a failed validation?
You could set the ValidationRule.ValidationStep property for your validation rules to ValidationStep.UpdatedValue. This first updates the source, and then performs validation. That means, your property setter should be called even though your validation fails. Note that this property is only available from .NET 3.5 SP1 upwards. For more details, see this blog post (paragraph "How do I use it? (Part 1)").
How I handle this in my view model classes:
public class MyViewModel : INotifyPropertyChanged, IDataErrorInfo
{
private Dictionary<string, string> _Errors = new Dictionary<string, string>();
public object SomeProperty
{
get { return _SomeProperty; }
set
{
if (value != _SomeProperty && !ValidationError("SomeProperty", value))
_SomeProperty = value;
OnPropertyChanged("SomeProperty");
}
}
}
private bool ValidationError(string propertyName, object value)
{
// I usually have a Dictionary<string, Func<object, string>> that maps property
// names to validation functions; the functions return null if the property
// is valid and an error message if not. You can embed the validation logic
// in the property setters, of course, but breaking them out as separate methods
// eases testing.
_Errors[propertyName] = _ValidationMethods[propertyName](value);
OnPropertyChanged("IsValid");
}
public bool IsValid
{
get { return !(_Errors.Where(x => x.Value != null).Any()));
}
public string this[string propertyName]
{
get
{
return (_Errors.ContainsKey(propertyName))
? _Errors[propertyName]
: null;
}
}
}
It's a little awkward to get this all set up at first, but once you've done it, you have a simple and straightforward way to report validation errors to the UI (via the DataErrorValidationRule), a straightforward way to know whether any given property is valid or not (check _Errors), and an IsValid property that tells you whether or not the whole view model is valid. (Also, you can extend the IsValid property to handle the case where all the properties of the view model are valid but the view model itself is not, e.g. two mutually exclusive flags are both set.) And as long as you make them internal, the validation methods can be unit tested via NUnit or whatever.
I should add that the above code is off the top of my head and may or may not work as written - my actual working code is in a base class and has a lot of other things baked into it that would just be confusing.
I have implemented IDataErrorInfo in one of my classes to validate a property of that class. The property is bound to a control on my wpf user control. The validataion works fine, except there is one vital flaw.
It seems to be calling the IDataErrorInfo member public string this[string columnName] before the property is updated, so when I check the value of the property being changed it contains the previous value not the one just entered. Therefore, the validation is always one step behind. This means that I can't check for incorrect values that have just been entered.
Is there any way of forcing this validation to be called after the property has been updated and not before. I have tried changing the UpdateSourceTrigger to both LostFocus and PropertyChanged but they still report the previous value, just at different times.
Thanks.
The behavior that you are referring to can be reproduced when property change notifications are sent before the property is assigned.
public string FirstName
{
get { return _firstName; }
set
{
if (this.PropertyChanged != null)
{
this.PropertyChanged
(this, new PropertyChangedEventArgs("FirstName"));
}
_firstName = value;
}
}
May be calling the change notification after you have actually set the value may do the trick. And just for the record I don't call property changed notification like this!
I am having problems using a ASP.NET Regular Expression Validator on text boxes.
This is a condensed version of my code:
RegularExpressionValidator regex = new RegularExpressionValidator();
regex.ID = "TextBoxRegExValidator" + ((AVPEditControl)avpControl).ThisFieldRID.ToString(); //random name
regex.ControlToValidate = ((AVPEditControl)avpControl).TextControlID; //this is valid.
regex.ValidationExpression = "\d{3}-\d{2}-\d{4}";
regex.Text = "epic fail";
//later, in an event handler
regex.Display = ValidatorDisplay.None;
regex.ErrorMessage = "";
regex.Validate(); //ERROR
bool valid = AVPEdit.Validator.IsValid;
Where I marked "ERROR" Is where I get a NullReferenceException thrown. I do not see what I am missing here, because I confirmed with a debugger that regex is not null in that context, and neither is the control that it validates.
I wish to have more fine grained control over how the error message is displayed,so thats why I chose not to hook regex into any Panels or such.
Why would I possibly be getting a null reference from that? (Is this a bug in .NET?)
Also, note that this works when I set Visible to 0, but that makes it so IsValid is always true.
All the ASP.NET validators must be part of a Page in order to function. You'll note that the Validate method does not return a value; this is because it is not intended to be used the way you're using it.
Inside the Validate method, it is attempting to look up the control by its ID and without a parent naming container, it has no ability to do so. The way you're doing it, it has no value to validate against (because it won't be able to find the control).
I would do one of the following:
1) Put the validator in the ASPX, then use its Validate method and check the IsValid property afterwards. Just set Display to None and it shouldn't show up in your UI.
2) Just run the regex manually. You're writing a lot more code here than would be necessary if you would just use Regex.IsMatch.
(Note that if you use Reflector, browse to RegularExpressionValidator, you'll see where it will attempt to call out to this.NamingContainer among other things that would be null without being part of a control collection)
I think you should add it to your controls collection, maybe inside an invisible div control to make it work.
But If you want to validate your textbox programmatically, why don't you just write a method that uses your pattern to validate control and returns validity ?
I think if you want to use code behind for validation, you can use something like this
Match m = Regex.Match(yourtext,"\d{3}-\d{2}-\d{4}")
if(m.Success)
{
//valid
}
else
{
//invalid
}