IValueConverter with error handling - wpf

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?

Related

Are the "nice" features of WPF really that nice? Or are they too controlling? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance.
Closed 10 years ago.
So I'm fairly new to MVVM and I have been struggling with a few issues regarding user input validation. WPF has some built-in features that seem to work like "magic", and generally, I know "magic" is not good.
For Example: If you bind a TextBox to a Property that has a type of double and the user enters "hello" into that TextBox, WPF automatically displays a red border around the TextBox notifying the user that the input is invalid.
This is all well and good, but it does seem like "magic". I was told by an experienced developer that WPF and app builders that are similar want to have too much control. He said that in web development the View would not know what type the Property is. Which makes sense to me. So this leads me to my general question - Should a WPF View understand property types? - If instead I declared the Property type as a string I could then have complete control over the view. Instead of having to work around WPF's "smart" TextBox "magic".
An alternative way to phrase my question is - Should Property types be declared in the Model or ViewModel?
I understand that if you declare the Property type in the Model as a double and as a string in the ViewModel it must be parsed in the Model. In most examples of MVVM applications I have looked at, the Property types are similar across the entire application, but I think that a "dumb" view that doesn't understand what it is working with would be much better.
Back to my example: If the Property were declared as a String you could completely control the format necessary for input and prevent invalid input all-together. This seems like a much better solution than trusting the WPF TextBox.
Yes, I think that feature of WPF is "that nice" :)
WPF has two layers: a data layer and a UI layer.
The data layer contains your data. If you have a number in your data, it should be of a numeric data type, not a string data type.
The UI layer (XAML) is only meant to provide a user-friendly interface for the data so that users can easily interact with the data layer. For example, if you have a data layer containing a numeric value and you want the user to be able to edit that value, you might choose to display your number using a TextBox.
If you force your data layer to use a string instead of a number just because the UI layer is using a TextBox to display the data, then you are letting the UI control your application, which is not how WPF should work. In addition, blending the two layers together like this makes it much harder to maintain in the future. For example, what happens if you decide to change the TextBox to a NumericUpDown UI control? Now you have to go modify your data layer to make a UI change.
In regards to your particular example, when you bind a TextBox to a double and type in a string like "hello", what actually occurs is that WPF tries to set your double value to a string value, and that throws an exception.
That exception is what causes the red border to appear around the TextBox and an error message to display, not any special handling. You could just as easily throw an exception in the setter for your double property, and the same thing would occur.
I wouldn't really call that "magic", just exception handling :)
But to avoid having to throw exceptions anytime you want to validate input, WPF provides the IDataErrorInfo interface which you can use to validate your property without throwing exceptions. The UI will react to errors raised with this interface the same way it would react to Exceptions.
Yes it should.
Karl Shifflett has a great article about it. Input Validation – UI Exceptions & Model Validation Errors
The solution is to detect invalid input. Data binding pipeline will throw exception when user input invalid data type. When it happens handle it on View then add error messages on ViewModel so that you could use it when needed.
WPF by default swallow that data binding exception, but you could add a handler on Loaded event in your View class.
_errorEventRoutedEventHandler = new RoutedEventHandler(ExceptionValidationErrorHandler);
this.AddHandler(System.Windows.Controls.Validation.ErrorEvent, _errorEventRoutedEventHandler, true);
Implement the handler
private void ExceptionValidationErrorHandler(object sender, RoutedEventArgs e)
{
// Add logic to handle this invalid data type exception.
// Add error messages to viewmodel, show notification dialog, etc
...
}
Set these properties on XAML binding NotifyOnValidationError, ValidatesOnDataErrors, ValidatesOnExceptions to true.
Text="{Binding UnitPrice, StringFormat=c, NotifyOnValidationError=True, ValidatesOnDataErrors=True, ValidatesOnExceptions=True}"
That's it.
Since you´re using a strong typed language, you're going to need validation sooner or later. I'm not sure what you would want to achieve by not using a form of validation that is already at hand. Don't forget that you can modify your view to do what ever you want when an invalid input is given. If you don't want any exceptions thrown (as explained by #Rachel), using a string property will likely prevent them.
Declaration
Properties connected to your database are declared in the Model. Properties you need to transform the Model into something userfriendly, are declared in the ViewModel. For example, we have a value (valueA) that is stored in the database. valueA is calculated by using two inputfields the user has available (valueB and valueC). In this case valueA is declared in your Model, but valueB and valueC are only declared in your ViewModel, since they don't need to be stored in the database. (Technically all three are available in your ViewModel but only valueA is declared in your Model)
The way I understand it:
Model Has properties that are stored in the database
ViewModel Converts the Model to something a user can handle (and vice versa).
View Is more or less the 'input area for your ViewModel' in which the user is aided by the use of graphics.

Approaches to WPF binding validation?

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.

MVVM detect Validation.HasError in View Model

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.

Dependency Property Uses in WPF

I am having a hard time figuring out good reasons for the dependency property. Why the System.Controls.TextBox "Text" property a dependency property and not a normal property? What benefits does it serve being a dependency property?
One of the things I am trying to accomplish is to add a ValidationRules property to my UserControl which will contain other validation rules. Like here:
<customControls:RequiredTextBox.ValidationRules>
<validators:NotNullOrEmptyValidationRule ErrorMessage="FirstName cannot be null or empty"/>
</customControls:RequiredTextBox.ValidationRules>
The problem is that I am not sure if ValidationRules property should be DependencyProperty or just a normal property.
The above code gives the following error:
{"Cannot add element to 'ValidationRules'; the property value is null. Error at object 'LearningWPF.ValidationRules.NotNullOrEmptyValidationRule' in markup file 'LearningWPF;component/addcustomerwindow.xaml' Line 35 Position 66."}
Here is the ValidationRules property:
public static readonly DependencyProperty ValidationRulesProperty =
DependencyProperty.Register("ValidationRules",
typeof (Collection<ValidationRule>), typeof (RequiredTextBox),
new FrameworkPropertyMetadata(null));
public Collection<ValidationRule> ValidationRules
{
get { return (Collection<ValidationRule>)GetValue(ValidationRulesProperty); }
set { SetValue(ValidationRulesProperty, value); }
}
The benefits are primarily two fold:
Firstly a dependency property is only created when it is used, this means the TextBox class can be very efficient, with a low memory footprint since it has a minimal number of real properties taking up space on the heap. This is especially important in WPF where all controls are just collections of more and more specific types. If each of those inner types declared tens of properties to define behaviour and look then a high level control like a button would end up having the size of a class with something in the ballpark of a hundred properties.
Secondly dependency properties can be tied to an object other than the type that they are created for. This allows the case where a control can set a Grid.Column property, which the Grid control can read and use for layout. This means that we don't hundreds of decorator classes supplying tiny pieces of functionality required by other controls. This means that xmal is far more intuitive and readable.
Edited to address the example in your revised question:
While your validation property won't gain much benefit from being a dependency property (basically out of the reasons in all the answers so far I can only really see my comment of memory footprint coming in to play), and it certainly isn't advantageous as it is in the case of the Text property of a text box where you may want to bind it, or change it based on some other input, I would still implement it as a dependency property. My reasoning for this is simple; you don't gain much, but it also doesn't cost you anything - I have never wished I had used a basic property in a custom control whereas when I first started writing them I was constantly upgrading my basic properties to dependencies because I wanted some extra functionality.
Simply put, while the dependency property is more complex to define that a normal property I would still use it as the de facto standard for WPF controls unless there was some good reason to do otherwise. In much the same way as a property is the standard for classes, even though a field is easier to implement.
The primary benefits I would say are:
First-class data binding support.
Clean Attached Property semantics
Property values which "depend".
That last point is key
Before Dependency Properties, having a value have a local value, an animatable value, an overridable value, a styleable value, a templatable value would require the declaration of multiple Properties/Fields/Dictionary entries, as well as complex state+precedence management.
Dependency Properties give you all these features out of the box, while declaring just ONE property.
That being said, in your case, you may not want to declare your ValidationRules as a DependencyProperty if you won't need to take advantage of these features.
If you do, you'll want to have different handling for your collections (non-empty collections for example). In this particular example, I would use Reflector and see how the .NET TextBox implements their validation collections, and see if you can reuse or copy the code.
There's no point re-inventing the wheel unless you're certain your wheel will be better. My personal experience is that my reinvented wheels tend to be missing things ;).
As Martin Harris already pointed out, DependencyProperties can limit the memory footprint by throwing the property values into a dictionary, however this can (and I believe was?) done by MSFT before the advent of DependencyProperties.
Martin also mentions Attached Properties, but those were also available (at least in designer) before the advent of DependencyProperties. The Attached Property implementation using DependencyProperties is much cleaner.
Dependency Properties are required if you want to use binding to populate the value of a property. If it was just a normal property, you wouldn't be able to bind the Text property to a property of your View Model object, for example.

Is this a crazy way to handle multi Validation types with IDataError and WPF?

We are using the standard method for our controls to report broken BO rules. This is done via the interface IDataError in our BO’s and in XAML the control is bound to the BO’s property etc. This approach works OK. But we need to show 2 types of visuals in the UI depending on the type (or category if you like) of the invalidation error. If it’s a required field then we show a CueBanner (water mark) but for other types we change the colour of the controls boarder. In both scenarios we set the tool type of the error message.
The Problem with IDataError is that it doesn’t support a method/property to distinguish between error types.
The only way I can do that is by examining the error text, required field text must contain the key word “required”. The following approach doesn’t feel right but it’s the only way I can determine the type of error and then deal with it accordingly. All required field rules must have as part of the error text “required field”.
To make this all work I have created a custom dependency property called ErrorMessage. In my ResourceDictionary I have a Style.Trigger for Validation.HasError. In there I set my dependency properties value to the ErrorContent. Now when my dependency properties value changes I can examine the text and set the Validation.SetErrorTemplate( myControl, newErrorTemplate) to the template to suit the error type. I have to wire up a few events to the control such as lost and got focus to manage removing or adding the cueBanner template but the whole thing will work. It’s just that I’m not sure it’s the best way to do it.
PS. When I set the ErrorTemplate i’m doing this in code, thats building and adding it. Is there a way to point Validation.SetErrorTemplate to a static resource keeping in mind that I need to switch between at least 2 types?
Your thoughts please..
Would it be possible to derive an interface IDataError that adds an extra property which is an enumeration of the error type. Then you could try and bind against it.
If you're okay with an (untested)approach that suffers a little bit of clarity, then you could do the following:
throw an exception instead of returning an string with the IDataErrorInfo Interface. In your ErrorTemplate, you can access the ValidationErrors (and the ValidationError.Exception Property).
Then, you use a DataTrigger on the Exception in combination with a converter, that checks for the right Exception-Type and return true or false. It should be enough to do the job.

Resources