I'm rather new to WP7 dev and I'm trying to play with data binding. I have an XML file and I want to represent it in a ListBox. I've made a ModelView on which I make a Linq query, the result of which I want to put in a ListBox. I've seen that many examples of DataBinding use the ObservableCollection class. I would like to use Linq to get the results instead of looping row by row, but if I use the IEnumerable instead of ObservableCollection, DataBinding does not work. Is that normal?
Silverlight works on a property changed mechanism to be notified when a property has changed in order to update a data binding. You can either use dependency properties (highly unlikely for a view model) or implement the INotifyPropertyChanged interface in your view model class.
In the case of ObservableCollection, it actually raises the CollectionChanged event when it's contents change (add/remove/insert), which also prompts the data binding to update. In your case, by binding to an IEnumerable, the data binding mechanism doesn't know when the contents has changed because there are no events raised.
If every action results in a new list, then you're not gaining anything by creating an ObservableCollection each time you re-query. So you'll need to implement the INotifyPropertyChanged interface and raise property change notification for yrou IEnumerable property when you re-query.
If you have items to add/remove each time you re-query, then creating an ObservableCollection the first time and then calling Add/Remove on each query will work just fine.
I guess it has to be an IList to work. IEnumerable won't work.
Try adding .ToList() to your LINQ query to convert it to List<T>.
As for ObservableCollection<T>, you need to use it if you plan to change items in that collection so that the UI automatically refreshes itself.
You can create an ObservableCollection from an enumerable by passing it to one of the constructors for the OC.
ObservableCollection<Foo> x = new ObservableCollection<Foo>(enumerable);
Courtesy of Cast LINQ result to ObservableCollection
Of course, this only applies if you want to avoid looping through the records yourself and don't have a reason due to behaviour in the code.
but if I use the IEnumerable instead of ObservableCollection, DataBinding does not work
Using an IEnumerable for your list of data items is not the problem, in fact the definition for the ItemsSource property on the ListBox is:
public IEnumerable ItemsSource { get; set; }
Most likely the issue is that your property is not notifying when its value has changed (use the INotifyPropertyChanged interface).
The ObservableCollection type is a collection that implements INotifyCollectionChanged, so you can easily tell when the collection itself has changed, although this doesn't notify you when the properties on the collection items themselves have changed. It also implements INotifyPropertyChanged, which is most likely why your data binding was working on your property in your ViewModel. The reason why the ObservableCollection is good to use in this case is because you can just add and remove items to the collection to update the list based control, you don't have to rebind it (or rebuild a list).
So if you bind to a IEnumerable<> property, make sure you raise a notification that the property has changed, and be aware that adding/removing individual items will not get reflected automatically in the UI unless you devise a way of notifying that the bound property has changed (which would be a bit of a hack).
Related
I have a Code First, CTP5 data context. I have a WPF app with a DataGrid. I set its DataContext like:
dataGrid.DataContext = _context.Customers.Local;
then I add a few entities using
_context.Customers.Add(customer1); and so on
_context.SaveChanges();
Then, I give these customers (a list of the customers) to another class to do some work on them.
customerUpdater.Update(customers);
That takes a long time and it updates properties of each customer while it's working. e.g.
foreach(var customer in customers) { customer.Name = "updated name"; }
I'm not seeing those updates in my WPF UI though! All I see are the original list of unaltered customers. Customers.Local is an ObservableCollection though, so I don't understand why I'm not seeing the updates in the UI.
I don't want to call SaveChanges() every time a property update occurs, it would be nearly constantly. Can someone tell me why this won't update?
If Customers.Local is an observableCollection, and you update the property "name" of one of their items, you are not seeing the updates because you are not modifying the observable collection, what you are modifying is the value of a property of one of the items (customer) present in the observableCollection, but the observableCollection will not send any notifications to the UI because it remains unchanged (it has the same number of items)
If you want the UI to be notified when you update the property name of a customer, you have to make the customer class to implement the INotifyPropertyChanged interface.
http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx
I have my MVVM and the model consists of a number of related classes, but for the sake of this question we'll focus on just four.
GrandParentModel, ParentModel, ChildModel and Contact.
These all inherit from ModelBase which has an implementation of INotifyPropertyChanged on it.
So each of the three models has a Contact property. If Child doesn't have a property it is supposed to look to Parent, and if Parent is blank it will look to GrandParent. If the contact changes at the grandparent level I'd like any dependants, ie any sub parents and their children to raise a PropertyChanged event for their Contact too.
I think everything I'm going to do will be supported by the DependencyProperty system, but I don't want to use that as this is my Model, separation of concerns and all that. So I'm putting together a mini implementation, which is all fine.
My question is has anyone been down this path before and is there anything I should be worried about in the future? My Spidey-Senses are tingling and I don't know why.
Thanks
Ian
Edit: The relationship between the objects here is that a grandparent has any number of parents has any number of children. My current model has a property on each which points at the parent (null in the case of a grandparent) and a parent/grandparent has a collection of child objects.
I've been down this path, and it's not pretty. Basically you have to subscribe to the PropertyChanged event of ParentModel from your ChildModel. You have to take care if your child can change parents. Then when you get notified of a change in the parent from the child's point of view, you have to raise your own PropertyChanged event on the child. It gets ugly because you can end up with hanging event handlers that you forgot to clean up.
A better method would be to create your own Model-specific analog to DependencyProperty. Basically in your constructor of ChildModel you "declare" that property Contact delegates to property Contact of object Parent when null. You do that using a little helper class that observes the PropertyChanged event on the ParentModel object and have it execute a PropertyChanged event on the child when appropriate. Also have it watch for the Parent property to change on the child.
You could use the MVVM Light message bus. Have the grandparent and parent all send a message when their Contact property changes. Have the child listen for those messages. When it gets a message, then check to see if it matches its own parent or grandparent, and raise a PropertyChanged event if necessary. This is better than either method above because you don't have to keep track of when your parent or grandparent changes. You're less likely to have bugs. It also uses weak references, so it won't hold on to objects the way event handlers do.
Now what I've been doing is getting away from having my model objects implement INotifyPropertyChanged. I introduced a Presenter layer between my Model and my ViewModel. The Presenter actually constructs a ViewModel out of small ViewModel "widgets" (one widget might be a ChangeValue<T> widget, for instance). I have a rules engine that tells the Presenter how to compose a ViewModel out of widgets for a given Model. The Presenter handles all user input (basically executing a lambda against the Model), but since it knows that a user action just took place, it knows that something in the Model might have changed. After the Model action is complete, it copies all of the data from the Model to the ViewModel. The ViewModel inspects the incoming data and raises a PropertyChanged event if the field actually changed. Obviously that's the most compliated way of doing it, but it gives you a really clean Model and neither the ViewModel nor the Presenter contains any Model (domain/business) logic.
I am using Entity Frameworks Code First. I have one entity that I need to keep a change history on. This entity has a double property and when it changes I need to record the amount change amount and date that it occurred. This means I need the old value the new value subtract and post ever time that value changes or when dbContect.SaveChanges() it called.
This project is really simple and I would like to keep it this way so I would prefer not add a service layer. I am simply making repository request in MVC controllers. (I know this is not pure but it is very agile)
How can I intercept changes to this entity so I can write to a change log?
You can listen for the ObjectContext.SavingChanges event, and then use the ObjectContext.ObjectStateManager property to look for the ObjectStateEntry(s) for the entity type that you are interested in.
ObjectStateEntry has properties to access the CurrentValues and OriginalValues, or only the original values for updatable properties using the GetUpdatableOriginalValues method.
Note: I have not tested this, but hopefully it will work for you.
I would like to know when entities in a certain database table are either created or updated. The application is essentially a CMS, and I need to know when changes are made to the content so that I can reindex them for searches.
I know that the autogenerated LINQ to EF class has overridable methods for when certain fields change, but I need to know when the whole object is created/updated, not just a single field. I tried putting it in OnCreated, only to find that meant OnObjectInitialized and not OnObjectInsertedIntoDBTable xD
I did some searching and came across this link. The "Entity State" section looks like its what I want, but I'm not sure how to use this information. Where do I override those methods?
Or perhaps there is a another/better way?
(I also need to know this for another part of the system, which will send notifications when certain content is changed. I would prefer this code to execute automatically when the insert/update occurs instead of placing it in a controller and hoping hoping I always call that method.)
You need to get ObjectStateEntry(s) from the ObjectStateManager property of the ObjectContect.
var objectStateEntries = this.ObjectStateManager.GetObjectStateEntries();
This entries contain every object state you've pulled down per context and what kind of actions where performed on them.
If you are using EF4 you can override the SaveChanges method to include this functionality. I've used this technique to audit every change that occurs in the database instead of triggers.
In MVVM pattern, how to notify all properties of the view model has changed? I don' t want to call all notifypropertychanged event of all properties.
I have an entity class and in view model I wrote all of the public fields of the entity as public properties. I want to rebind new entity and just write a single line of code to notify that all properties has changed?
Thanks for your help.
Just raise the PropertyChanged event with an empty string as the property name :
OnPropertyChanged(String.Empty);
Ok what I understood from your question is this..
View <> ViewModel <> Entity (with a bunch of properties)
View is bound to ViewModel, which delegates to Entity. You now want to replace the backing entity and signal the view to refresh to update to the newer entity.
I'd suggest implementing an indexer in the ViewModel which takes in a string (the name of the backing property). The ViewModel can be used as a cache if required, delegating to the backing entity only on a miss.
When you replace the entity, the viewModel clears its cache and fires NotifyPropertyChanged (in the indexer set) with String.Empty or null. Which I learned today, indicates all properties have changed.
This way you don't create n delegating properties in the ViewModel. A google search result shows that it has been tried at least once with success.