I'm using MVVM and have most of my validation done using IDataErrorInfo and my ViewModel has an IsValid property which checks the validity of each member that needs to be validated. However I have a couple of textboxes bound to ints that can't be null, so I'm using a ValidationRule to alert the user (with a more friendly message than the "value could not be converted" one) if they blank that field out as obviously the property setter never gets called so the IDataErrorInfo code isn't called.
The problem is that I have a Save button (which is a RelayCommand) which I want disabled if there is any validation error. So the CanExecute of that command checks the VM's IsValid property. But obviously if the user blanks my int field the IDataErrorInfo knows nothing about it and currently the button won't disabled. Is there a way that the ViewModel can detect that error?
I thought I'd found a solution here
http://wpfglue.wordpress.com/2009/12/03/forwarding-the-result-of-wpf-validation-in-mvvm/
but having translated it to C# I can't get it working (the Coerce callback is never called). I don't understand dependency properties and objects very well yet (very new to WPF) and this solution looks complicated to me.
The only thing I can think to do is to get rid of the validation rule and make a nullable int wrapper, put TargetNullValue='' in the binding and then I can check them for null in the IDataErrorInfo code. I would prefer not to do this if there's a better way.
why not use string properties instead of int with IDataErrorInfo validation in your viewmodel? in your savecommand you can safely convert your string to your int values, if IDataErrorInfo has no errors of course. Using string properties with IDataErrorInfo is the most easy way.
edit: one more think, there is another problem if you not use string properties. say you have an int Property, and the user set a 10 in your textbox. so in your viewmodel you have the 10. now the user delete the 10 and set a abc in your textbox. your viewmodel still got the 10., because of the bindingconversationexception. thats why i almost use string properties. to be fair you can use behaviors for textbox to set a mask, so the user can not enter invalid data.
I can think of two strong options right away. One is to bind to a string property in your ViewModel, which in turn is programmed to only parse and store the underlying 'int' value if the string is determined to be valid. This ensures that your TextBox will always successfully store its databound value.
The second is to intercept the ValidationExceptions that occur in your View, storing them in your ViewModel via a custom Behavior. This article will essentially do exactly as you described in your question.
What you can try is BindingGroups and have a validation over the whole element, not just single properties. I used this for our modal dialogs to create a project for example, where certain settings must be set before finishing the dialog. This link explained it in good detail. This one is also quite detailed.
Related
I know this is a pretty broad problem, so I'm surprised I haven't found a good answer yet. Here's my situation:
I have a class named TimeConverter that I use quite often, which implements the IValueConverter interface converts a string containing an amount of time (such as "25:36") into an integer representing the number of minutes (which for the earlier example would be 1536). Currently, when someone enters something untranslatable (like "asdf") the converter returns DependencyProperty.UnsetValue, which causes the bound element (usually a TextBox) to show a red border. Here's the problem, the class containing the integer property on the other end of the binding needs to know that there is a conversion error.
I've found this to be quite difficult and almost impossible to do without the data item having a reference to the bound TextBox. If I get a reference to the TextBox, I can use the Validation attached properties, but i feel like that's sloppy and its also not always possible. Currently I have one of these bindings in place on a TextBox, inside a Setter, inside a Style, inside a DataTemplate (pretty far removed from the visual tree), which also prevents me from using the Validation.Error even for notification. And of course the simple answer of binding Validation.HasError to the data item doesn't work because of how the property is declared.
So how CAN I notify the data item when the conversion fails?
I'm struggling to find a satisfactory approach to data validation in WPF/MVVM. I've been using IDataErrorInfo but if I bind a textbox to (say) an int property, and enter a non-numeric value, WPF generates its own validation message ("value 'xyz' could not be converted"). The control does get highlighted as being in error, but my viewmodel is unaware that the property is in an invalid state, as the binding (and therefore the IDataErrorInfo validation) never happened.
I haven't looked into custom validators yet. Using these is it possible to notify the view model that there are errors? I'm a bit reluctant to use them as it seems excessive to create validator classes for each of the many rules that a complex application requires. Maybe I could use a mixture of the two approaches, i.e. a basic custom validator that ensures that the input is numeric, and IDataErrorInfo for the more complex stuff?
I'm also struggling to validate "related" properties using IDataErrorInfo. Say my model has "Min" and "Max" properties and I want to ensure that Min is less than Max. If I change the "Min" textbox to be greater than Max, the control would be correctly marked as invalid. If I now change "Max" to be greater than "Min", the "Min" textbox validation state does not get cleared down (presumably because "Min" hasn't changed and therefore doesn't get validated again). What's the best approach for this situation?
I would be interested to know how others have tackled WPF validation. Are there any improvements to WPF validation in .Net 4.5?
Suspect you are aware of this but set never even gets called if the type does not match (or cannot be converted).
Had this problem with an empty TextBox bound to an Int? as the TextBox was passing String.Empty not null. So used a converter to convert String.Empty to null.
A TextBox is going to accept text. There is no getting around that.
You can bind to string so everything gets through to the set.
Or you can handle the keydown event at the UI and only allow numeric and bind to Int. Then in the validation determine if the value is in range.
I have a Silverlight control which has a ListBox showing a series of email addresses. The data source is an ObservableCollection of strings (one per email) in the ViewModel. Simple enough!
I wanted to allow in-place editing of the list, by changing the data template from a TextBlock to a TextBox, with a two-way binding.
The problem is this: How do I validate the user edit is a valid email address?
I don't want to save the bound text to the list unless it's valid. I can't throw an exception as it's bound to a string, so there's no Set method to modify.
The only solution I can think of is to create a dummy class with a single Email property just so I can validate the value. I can't believe that's the best way.
Well you've got bigger problems than just the validation. You can't use TwoWay binding when the source object is a string.
It does make some sense to create an AddressEntry class that has an EmailAddress string property. That way you can make two way binding work and it gives you somewhere to write your validation.
I'm trying figure out the best way to validate user input and I've been looking at ValidationRule and IDataErrorInfo. I have a VM and a model and I want to ensure a user does not enter alpha char's into multiple textbox's bound to doubles (or ints).
I'm running into 3 issues
1) When I use the ValidationRule the method returns a 'ValidationResult' but where does that go? Is it stored as property some where?
2) If I user IDataErrorInfo and enter some alpha char's it is never called (it is if numbers are entered) Is that expected? *
*(I thought maybe a value converter might help here but I feel like I'm mixing together two separate concepts)
3) Really what I want to do is do a validation at the end when a user clicks 'Save' and check all the values. So maybe using these two methods aren't what i need as per 1838300. Is that correct, these really are only for 'on the fly' validation?
My thought on point 3 was if the result of the ValidationRule was store somewhere I could check that for each control or where ever it is stored. Or if IDataErrorInfo was called I could manually store some Boolean for each control and check those.
Any thoughts or ideas?
Thanks!
There are a couple of things, you need to know:
When the type of the dependencyproperty is not the same as the underlying value - an automatic conversion is tried if no valueconverter is present.
This is all part of the normal binding engine. So, since your textbox input doesn't convert well to ints/doubles with alpha chars, an exception is thrown and will be continually thrown until you correct the value of the dependency property (here the TextBox's Text property) - the property setter of the underlying dataobject is never reached now.
You can verify this behaviour if you look in your output window for exceptions when you alter the text in the textbox. See this article to see how to properly implement Validation and IDataErrorInfo: link.
You might be interested in the BookLibrary sample application of the WPF Application Framework (WAF). It shows how to use validation in WPF and how to control the Save button when validation errors exists.
I'm looking at developing a simple validation framework for WPF (the IDataErrorInfo method doesn't provide enough info for my needs), and am wondering if there is a way to be notified when a Property is going to validate? Please note that I need to know any time it is going to attempt validation rather than only when there is an error (so NotifyOnValidationError doesn't cut it)
Alternatively, my ultimate goal is simply to package more information than just an error string into my validations (How critical is the error, links for more info, etc.) while still allowing the validation to be driven by the data object (IDataErrorInfo style). If anyone can point me to a method for doing that then I'll be perfectly happy as well. :)
The problem you are going to run into is that WPF databinding and validation are tied to the IDataErrorInfo interface. The bindings check for validation based on the UpdateSourceTrigger property of the binding. So if your binding has "UpdateSourceTrigger=PropertyChanged" then everytime the property changes it calls the item["MyProperty"] which is where you would return information as to whether of not your property is valid. If it's set to "LostFocus" then it checks whenever the control loses focus. The binding also requires the "ValidatesOnDataErrors=True" in order for it to force validation on your bound entity.
I think your best bet would be to create a class that implements IDataErrorInfo and then supply more detailed information based on the severity of the error.
You need to look into inheriting from ValidationRule and then adding the new rule to all you binding objects.