Force WPF component to validate when an event is raised - wpf

in my MVVM application I have a list of element implementing IDataErrorInfo and INotifyPropertyChanged
the view validate the VM objects when a propertychanged event is raised.
the problem is that the validation result depends not only by the internal state of the object but also by the "enviroment" that is the other objects belonging to the list.
So I need that the validation is called on all the elements of the list every time that an object is deleted or updated.
How can i force the validaiton in this way?

within the VM which holds the list, each time your list changes, iterate over the list and tell each object to raise property change notification either on the properties you know might be invalid or just every property by setting the property name to an empty string.
It sounds like your validation may be across multiple objects, in which case you need to run your validation from the VM mentioned above and set error messages in the appropriate objects in the collection and then raise the property changed event on those objects.
I have done this previously by having a SetErrorMessage(string string) public method on the objects implementing IDataErrorInfo, and a public OnPropertyChanged(string) method so that I could set errors and raise contextual property changed events from outside the object.
The errors would be stored in a dictionary and the this[string] property would look up the dictionary for errors as well as run its own validation.

Hey I have an answer to your question. The default list called ObservableCollection will raise an event only if elements are added or deleted. If the element changes property wont be raised.
You can subclass ObservableCollection and add event for every item. There is a very nice implementation in this link given by a fellow from StackOverFlow.
ObservableCollection that also monitors changes on the elements in collection
Its too good, I have tried and used. It works superb. Hope it helps you and puts you in right direction!!!

Related

Using dependency property default value as binding source

Having to work with a legacy silverlight application I ran into a strange piece of code. The viewmodel has a List dependency property as binding source for the grid. This DP has a default value, an other List that is used globally in the app. This is used to easily share entity data between different parts of the application.
DependencyProperty MyEntitiesProperty = DependencyProperty.Register("MyEntities", typeof(List<Entity>), typeof(...), new PropertyMetadata(Global.Entities));
Now, when the list is changed (on user actions), the global list is repopulated from database but MyEntities is never set explicitly. This does not work: the grid (the binding target) never changes. So its a wrong solution.
I speculate that the idea behind all this could have been been the following: if you have a DP with a given value and you never set a local value for it then the effective value of the DP will be the default value. If the 'underlying' default value is changed, the changes are reflected in the effective value.
If it worked, it was a nice way of sharing data between independent viewmodels without fiddling with property change events and such.
What is wrong here? Is it a big misunderstanding of how DPs work or the idea was ok and some implementation details were missed?
Please comment if something is not clear.
Well, taking also your comment into account, it is a big misunderstanding of how DPs work. Let me explain:
Setting a globally known list as the default value of MyEntities might not be a pattern I recommend, but is technically not faulty and can be done to share a list. MyEntities now holds a reference to this very list.
If you now replace the global list with a new list instance, the old instance does not cease to exist. Your property MyEntities still holds a reference to the old list. The value of a DP is only updated automatically if it is bound via Binding to either an ordinary property that is wired with the INotifyPropertyChanged mechanism or another DP.
Setting a default value happens neither via a Binding to an ordinary property nor via a Binding to another DP, it is just a plain old object reference.
I can think of several ways to correct the situation:
First solution
If the global list implements INotifyCollectionChanged (e.g. ObservableCollection, DependencyObjectCollection) you can - instead of creating a new list instance - just delete the old items from the list and add the new items. The views that have a reference to the list will perform an update as soon as they receive the associated CollectionChanged event.
Second solution
Make sure the Global.Entities list is available and always up-to-date as a public property (wired with INotifyPropertyChanged) on the DataContext of the root view. Now when you want a nested view somewhere deep down inside the UI tree to be connected to this Global.Entities list you can bind it to the root view's DataContext' public list property.
<MyRootView>
... nested views spread across multiple files ...
<MyNestedEntitiesListDisplay
MyEntities="{Binding
Path=DataConext.GlobalEntities,
RelativeSource={RelativeSource AncestorType=MyRootView}}"/>

WPF: How to create a collection that can be bound to

My app has a background thread that periodically retrieves data from an external source, in the form of key/value pairs. I would like to expose this data for binding, presumably by storing them in some kind of static(?) model, as the data will be needed by numerous views throughout my app. There are potentially hundreds of these keys, and may be different for each customer, so I can't simply create an INotifyPropertyChanged model with a property for each value.
The app has multiple views visible at any one time, and each of these will have numerous controls (usually textboxes) that I want to bind to individual items in the above collection. When a value in the collection is updated, any controls bound to only that item should change to reflect the new value. I'm assuming an ObservableCollection wouldn't be suitable here, as a change to a single item will result in all controls updating, regardless of which item they are bound to?
To throw a further complexity into the mix, some values (which are numeric) will need formatting for display, e.g. number of decimal places, or adding a suffix such as "volts". The formatting rules are user-defined so I can't hardcode them into (say) the XAML binding's StringFormat expression. Ideally I should be able to access both the raw value (e.g. for calculations), and the formatted version (for display purposes). I'm sure it must be possible to achieve the latter using some clever WPF feature!
I would appreciate any pointers on how I can solve these requirements.
Edit: it's worth mentioning that I've previously tried implementing the model as some kind of collection. The problem is that it won't be initially populated with all values, and these only get added some time later. When they do eventually get added, a bound control doesn't update - presumably because it wasn't initially able to bind to the missing value.
I would take a different approach, namely a variation of Event Aggregation. I would have a single class that manages the overall collection (probably a singleton class like franssu suggested), but instead of binding directly to the collection in that class you create smaller models that are more specific to the individual views.
When your main model receives a new item, it publishes an event, which is consumed by the smaller models who can inspect the new item and determine whether or not they should add that item to their internal collection (the one the individual views are bound to). If it doesn't "belong" to their view, they can simply ignore the event.
You could use similar event publishing for updates to items and such, although if you're binding to the actual items you probably don't need that.
Just implement the INotifyCollectionChanged Interface and the INotifyPropertyChanged and you ll get a Collection like the ObservableCollection.
But rember if you select a Item from your Collection (as example a ObservableCollection) and you change that item your other controls won t update. So if you have a class Person in your Collection and you change the name of one person the other controls won t get the new name of the person.
Inside the Person object you still have to implement the INotifyPropertyChanged Interface and raise the event when your name changes.
So what I want to tell you is: A Collection with the interface INotifyCollectionChanged will only tell the bound controls: There is a new Item, there has been a item removed or a items index changed BUT not if the item itself changes.
So you ll need a Collection that provides the points above and a Item contained by the collection that raises events if a property of it changes.
ObservableCollection is perfect here. You should find that a standard ItemsControl bound to an ObservableCollection will only update the controls of the items that have changed, not every item in the collection.
This is the reason ObservableCollection exists - the events that it raises specifically identify items that have changed, so that the UI can handle them sensibly.
I've tested this locally with a small WPF app and it works fine. Worth noting, though, that a virtualised items panel would probbaly appear to break this behaviour when it scrolls...
EDIT: rereading your question, you actually say "When a value in the collection is updated..." If your collection contains instances of a class, and you update properties on the class, you don't even need ObservableCollection for this to work - you just need the class to implement INotifyPropertyChanged.

Silverlight: Can't force update of binding to collection via INPC?

Say I have a ListBox that is bound to an observable collection on my view model, where the data item is a simple class that has a Name and a Value property.
When I add or remove items from the view model collection, the ListBox updates automatically as I would expect.
However, if I change the name of a data item, I want the ListBox to refresh as well, so I raise a property change for the view model property that exposes the observable collection after I've updated the name in code. The ListBox won't update however.
It's as if the binding is saying, well, the object you're giving me (the collection itself) is the same as the last one I had, so it hasn't really changed, has it? Silly programmer, telling me to refresh when I don't need to!
There are only a couple of ways I have found to work around this issue:
Raise an explicit Reset notification from the collection itself (requires subclassing of ObservableCollection to do this)
Recreate the list using a new observable collection, then raise the property change - the collection object is different now so the binding updates
Neither of these two ways are ideal, although the first method is definitely preferable - it really shouldn't be this hard to get a listbox to update!
Can anyone explain why bindings work this way, and if there is any way to change the behaviour so that the binding will always update on a property change notification, regardless of whether the source has changed or not?
It sounds to me like the items within your ObservableCollection do not implement INotifyPropertyChanged. You need to do this, so that when you change the Name property of an item in the collection, the UI is updated. From your description, the framework and your bound collection are working exactly as the should.

WPF Binding to IDictionary<int,MyType>.Values Doesn't Respond to Property Changes?

I am binding a ListView a property that essentially wraps the Values collection (ICollection) on a generic dictionary.
When the values in the dictionary change, I call OnNotifyPropertyChanged(property). I don't see the updates on the screen, with no binding errors.
When I change the property getter to return the Linq extension dictionary.Values.ToList(), without changing the signature of the property (ICollection) it works with no problem.
Any reason why the Values collection bind and notify properly without projecting to an IList<>?
Calling OnNotifyPropertyChanged() isn't exactly correct in this case, since the collection is still the same, however the items in the collection have changed. I don't know exactly how the WPF binding code works, but it might do a quick check to see if the reference it is binding to has changed, and if not it won't update the UI.
The reason that ToList() works is because each time it is called, a new instance of List<T> is returned, so when OnNotifyPropertyChanged() is fired, WPF picks up on the change and updates all of its bindings.
I don't know if this is possible or not, but the ideal solution would be to use a collection for bindings that implements INotifyCollectionChanged. This will fire events that WPF monitors so that items can be added, removed, etc. from the UI as appropriate.

Validating collection elements in WPF

I would like to know how people are going about validating collections in WPF. Lets say for example that I have an observable collection of ViewModels that I am binding to the items source of a grid, and the user can add new rows to the grid and needs to fill them.
First of all I need to validate on each row to ensure that required fields of each ViewModel are filled in. This is fine and simple to do for each row.
However, the second level of validation is on the collection as a whole. For example i want to ensure that no two rows of the collection have the same identifier, or that no two rows have the same name. Im basically checking for duplicate properties within different rows. I also have more complex conditions where I must ensure that there is at least one item within the collection that has some property set.
How do I get a validation rule that would allow me to check these rules, validating on the whole collection rather than the individual items. I also want to print any validation error above the datagrid so that the user can fix the problem and the message will update or disappear as the user fixes each different rule.
Anyone have any experience of the proper way to do this?
The trick is to place your collection validation logic such that it's called when the ItemsControl's ItemsSource property changes. If you're using IDataErrorInfo on your view-model, then set ValidatesOnDataErrors=True on the ItemsSource binding and, when the bound collection property's name is passed into the interface's error indexer, run the logic to determine if the property is still valid or not. If you're using custom validation rules, then putting the rules into the ItemsSource binding should be fine, to.
Next, in your view-model, raise the PropertyChanged event for the ItemsSource-bound property whenever an event occurs which changes the collection's valid/invalid state. For example, if the collection needs a certain number of elements, then listen to the CollectionChanged event. Whenever the collection changes, raise the PropertyChanged event for the ItemsSource-bound property. This tells WPF that the property changed, which leads to its revalidation. Thus, your collection validation logic will run whenever the collection changes and, if the collection is invalid, WPF displays the error adorner or, if the collection becomes valid, WPF removes the adorner.

Resources