Event on validation - WPF - wpf

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.

Related

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.

Custom property dependant on other properties

Advance apologies for the event-style explanation; there's a lot of factors that I feel all play a role of their own. WPF is not my native framework of choice, and it probably shows. :)
Old situation: I had a window with several controls. Depending on their selections, I used multibindings and a converter to determine whether certain controls needed to be shown that inform the user about the implications of their changes before they'd eventually confirm them by OK (or simply dismissed by using Cancel). This worked perfectly.
Problem: Too many controls as time went by, too much clutter.
Solution: Put stuff in different Pages so it becomes easier to browse for the user. In order to have changes-to-be persist as a user arbitrarily browses between the pages, I create these dynamically and put them in a cache (Dictionary<string, BasePage>, see below), from which they will be pulled as the user chooses them.
Consequence: I need to decouple the bindings to the notification controls as the different options are now on different pages.
Solution? I put a BasePage class in that exposes certain abstract read-only properties that define the various aspects that the window needs to know about in order to do its notifications. For example, a bool requiresReboot property defines whether the current state of things on that page requires a reboot to take (full) effect. A specific page implements the property based on its controls.
Problem: I do not know how to keep create a proper binding that properly gets updated as the pages are changed. I tried giving my notification controls a binding to the Dictionary<string, BasePage> with a converter that checks all pages and the relevant property.
Questions:
1) How do I create a proper property for this purpose? I presume I need a DependancyProperty as I did a fair bit of reading on MSDN, but I can't figure out how this fits together.
2) How do I make a link between my custom property so that it allows (multiple) control(s) on a page to change that property? Do I use INotifyPropertyChanged somehow? My old example bound against several CheckBox.IsChecked properties in XAML. I am trying to avoid putting tons of events (OnChange, etc) on the controls as the original code did not need it and I have been told it makes for a messy solution for as far WPF is concerned.
3) Finally, I suspect I may need to change my Dictionary<string, BasePage> class to a custom implementation that implements some sort of INotifyPropertyChanged but for Collections? Observable Collection is the term I am looking for, I believe.
I hope someone is able to bridge the gap in my understanding of WPF (property) internals; I would very much appreciate it. A basic sample would be even better, but if it is too complicated, just a nudge in the right direction will do. Thank you. :)
It's been a while since I solved this, and while I cannot remember the exact cause of the problems, there were a few different issues that made up the bulk of the trouble I ran into.
I ended up making the Property in question a non-abstract DependencyProperty in the base class; it was the only way in which I could properly delegate the change notifications to the interface. Derived classes simply ended up binding it to their controls (with a proper Converter in the case extra logic was necessitated).
As Dictionary<string, BasePage> does not support any sort of change notification, I made an extra collection of ObservableCollection<BasePage> which I used for binding purposes.
However, such a collection does not propagate a change event when items inside of it has a property changed. Since this situation required that, and I was binding to the collection itself in the context of a property that does not have a Master<->Detail relationship like a DataGrid (which basically add their own OnPropertyChanged handlers to the binded object), I ended up subclassing a VeryObservableCollecton<>. This one listens to its own items, and throws a proper change event (I think it was an OnPropertyChanged from the INotifyPropertyChanged interface) so that the binding (or in this case a multi-binding) would refresh properly and allow my interface to update.
It is hardly the prettiest code, and it feels over-engineered, but at least it allows me to properly bind the UI to the data in this manner.

Validation When Using MVVM (WPF) with a DDD-Based Model

A common MVVM/WPF approach is to data-bind the UI's controls directly to the underlying model object. The model object may contain its own validation logic (perhaps exposed via IDataErrorInfo) or may be validated by a helper class checks a model object instance for errors. In either case, at times the model have invalid data in it and so be in an invalid state.
However, in the DDD world, the model is never to be in an invalid state. How do you suggest performing validation when using WPF and DDD?
Thanks,
Ben
I don't think the View in MVVM should be binding directly to the domain model, it really should be binding to a View Model instead. Then the View Model can be in an "invalid" state which can be reflected through IDataErrorInfo. Only later when a user operation (e.g. Save, OK, Apply) applies this to the underlying domain model should the domain model enforce validity, you can also prevent the apply by not allowing the operation in the UI.
Although I must say I've found that it's not always easy to do this without duplicating the validation logic to some extent.
I'm tending to think that a facade or similar layer should be used as the MVVM "model." This facade can be in an invalid state (unlike the DDD model). For validation, it can either contain its own logic or a tool like FluentValidation can be used. Once it is in a valid state, its "do action" function can be called. This will pass the data in the facade to the underlying DDD model. With this approach, at no point does the DDD model encounter invalid data.
With this approach, the facade and its validation logic could be used by multiple view/view model pairs, eliminating the validation logic duplication present when each view model does its own validation.
Validation belongs in your business logic (domain model). I suggest taking a look at FluentValidation for .NET.
I've actually had good luck having the ViewModel setter call the underlying Model object, and letting FluentValidation throw an exception. If you're using a WPF TextBox, the binding will keep working, but the TextBox will show a red outline (assuming you've used the syntax where the TextBox updates the ViewModel on each and every keystroke). Just don't throw an exception in the getter or you'll break the binding.
It's better to route all your communication from the ViewModel to the Model through some intermediary (I introduced a Presenter, but this can be as simple as passing the Model operation as a lambda to a callback on some mediator). When an exception happens while operating on the Model, the Presenter catches the exception and displays a friendly message to the user with the details from the exception. FluentValidation produces really nice default error messages for this purpose.

How to catch and display warnings to the user

Essentially the warning in our case is just a validation, we don't want to mark it as an error just a warning so the user knows. I was hoping to use the same or similar method used for validation. Currently I'm leaning towards implementing IDataErrorInfo. But I'd like to change the style on display and allow saving. Has anyone done anything similar? I don't want 2 separate solutions for validation.
during validation, set some corresponding properties.
eg: IsInWarning and IsInError.
set these properties according to the validation logic in the error handler and then use a datatemplate to style the items with triggers.
something like that?
(sorry no time to mock up an example now...)
WPF has a built-in mechanism for handling validation via IDataErrorInfo.
There is a good CodeProject article describing the process, but it basically comes down to supplying an ErrorTemplate that's used for items in an error state, and telling WPF to validate your objects. If they implement IDataError info, you can have their style change, plus use that to present error messages directly.

Should my ViewModel contain a URI or a string?

This is somewhat of a followup to my previous question, where people pointed me in the direction of MVVM.
I'm trying to understand exactly where the work is supposed to go in this framework. My view contains a textbox into which the user is meant to input a URI.
As far as I see, I have two choices:
Bind to a Uri object in my ViewModel, using a converter and validator to check if the URI is valid and convert it if it is. The ViewModel then ends up with either a valid Uri, or DependencyProperty.UnsetValue. (I am using something like this as a combined converter/validator; is this good MVVM practices?)
Bind to a string in my ViewModel, and do the conversion/validation as necessary for the ViewModel's code. I'm not entirely sure what the code is for having the ViewModel tell the view that the URI-string is invalid, though, and displaying appropriate validation errors.
I guess generally the question is about how and where to handle potentially invalid data in the MVVM framework. This doesn't seem to be covered in any of the basic introductions to MVVM that I've been browsing through. Thanks for your help in getting this all straight in my mind :).
In my opinion, you should have your validation framework, validate the input from the user, once it's confirmed as valid, is should be bound by a converter to a Uri property on the ViewModel.
It all depends how you setup your validation, but I would suggest that your validation should come before properties being set on the ViewModel.
Hope that helps!

Resources