I have a WPF application consuming data using Entity Framework 4 and Self-Tracking Entities. In which I have a window with 2 controls in it, one that shows the "Details" portion of an object using a ContentControl and templates from a merged resource dictionary. Another with a ListBox of Groups the object in question belongs to and a ComboBox of available groups it could belong towith a button wired up via a command to the control to add/remove items from the bound collection of Groups based on the SelectedItem of the ComboBox. All this is bound together by DependencyPropertys.
In my Window I have DP's for the Object, EditedItem we are editing and a read only property with a List of Group of the groups it could belong to and bind that to my controls via XAML.
SO....
If I create a new instance of one of my entities, set it's properties like so: (Really this is the exact code)
Employee employee = Context.CreateObject<Employee>();
employee.Name = "Joe Nobody's Brother Steve";
employee.Active = true;
employee.Username = "snobody";
Group group = Context.CreateObject<Group>();
group.Name = "Losers";
group.DisplayName = "Spirit Squad";
employee.Groups.Add(group);
And set it as my Window's EditedItem it works FLAWLESSLY!
If I however fetch this exact same entity from my Database the Groups ListBox is empty.
Any ideas?
It turns out I had made a mistake else where:
I needed to call:
ObjectContext.LoadProperty(entity, navigationProperty);
on my navigation properties for them to get populated. I think this has something to do with my objects all being derived from a core object and the fact that I select them using OfType on the ObjectSet of the core object. Or it could be behavior but I would think I would have encountered it before now.
But hey I'll take working, and this is easy enough to integrate into my selection methods and properties.
Chalk this one up to ignorance of EF4.
Related
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.
I created a new entity object and bound it to controls in another window (edit window). After modifying and saving I assigned a new entity object into the one in the main window. The old entity object is bound into a datagrid, now I want the datagrid to display the data that I had modified and saved.
ObjectContext.Refresh Method (RefreshMode, Object) seems to be what I want but I don't know how to use it correctly.
In short :
I have a main window with datagrid displaying the whole data of the table. Users can pick one row and edit it in a edit window. After saving, the datagrid should display what has been modified.
Your best bet here is to use an ObservableCollection as your data source for the datagrid instead of the query.
And look at implementing INotifyPropertyChanged interface in your Customer class.
The ObservableCollection is initially populated by the database query. User changes are made to elements within the ObservableCollection and once complete you then just need to trigger transferring the changes to wherever you originally obtained your list of Customer objects
By doing this changes made both to the collection of Customers and to individual Customer objects (if present within the datagrid) will be automatically updated for you.
edit
I must admit that I'm a bit rushed to offer up any code at the moment, but here's a pretty good article that explains how to use ObservableCollections and classes that implement INotifyPropertyChanged. It also has code examples, which although in VB.NET should give you enough of an idea to get started.
In effect you separate your code into distinct layers UI (View), business logic (View Model) and data layer (Model where your entity framework resides).
You bnd your datagrid to the ObservableCollection type property in your Customers class and your edit csutomer window is bound to as instance of your Customer class.
I have a custom panel control that is intended to be used as an itemspaneltemplate in a items control.
The itemscontrol will be databound to a data source.
This datasource is a List, and each item in the list is a custom business object.
In the application, the user is able to update each of these business objects in the list, and that fires the notification on property changed as expected.
Now my problem is here:
When the user updates the object's properties in the data source (the itms in the List) that the items control is bound to, my custom panel control is not able to get that notification, so as a result the items control does not get updated with the updated items in its view.
I tried using an ObservableCollection instead of List - the problem is still the same.
I must be missing something fundamental here... please help with any pointers, answers or solution.
Change notification in a collection is a bit tricky. Say you have a collection of Products. you can implement change notification is three different places.
Change notification in the Product class (implementing INotifyPropertyChanged in class Product)
Change notification in the collection itself (i.e. using ObservableCollection)
Change notification in the class that holds the collection, that is, implementing INotifyPropertyChanged on the class that contains the collection. (usually this would be the ViewModel under MVVM)
Those tree ways are not the same, and each is for a different situation.
Let's say that the collection is ObservableCollection<Product> Products {get;set;}
if you want changes in the product to register (i.e., if you're doing something like Products[0].Name = "New Product"; then #1 is the right one.
If you want to do Products.Add(new Product(...)) then #2 is the right one.
If you want to do Products = new ObservableCollection<Product>() then #3 is the correct one. This is especially tricky since i'm not changing the collection, but creating a new one, so the ObservableCollection won't help - I'd need to implement INPC in the containing class.
I'm trying to build a data entry form in wpf. To perform validation I apparently need to have an object attached in the datacontext of my grid. But how can I have one when I didn't create one yet?
How does it work?
For example, I have a screen with a datagrid. The datagrid contains users that were obtained from membership. Above the grid is a button: add user. When clicked a new window appears and the following can be entered: user name, password, email. To perform validation on the textboxes to see if they aren't empty. Now, it is my understanding that the way this works is by having an object attached to the window (datagrid datacontext). But how can I have it attached when it doesn't exist yet?
This is a case where MVVM design patterns are very useful.
Every WPF view has a corresponding view model object that the properties in the view are bound to. So your window with the data grid has a view model - its DataContext - and the view model has properties that are bound to properties in the view - e.g. the ItemsSource in the data grid is bound to a collection (see note 1).
The "add user" command (which is implemented as a RelayCommand in the window's view model) creates a new view (the new window) and its corresponding view model object (the new user), sets the view's DataContext to the view model, and calls ShowDialog to show the window. (See note 2.) If the user accepts the new object, ShowDialog returns true, and the logic in the command takes the view model object (which now contains whatever changes the user made) and uses the information in it to create a new model object and add it to the model. If the user cancels, ShowDialog returns false, and the command discards the view model object without creating a new model object.
Note 1: The collection here may be a collection of model objects, or it may be a collection of view model objects. It depends on whether or not you need anything that's not in the model for displaying the model objects in a data grid. It's common, in this kind of scenario, for the objects in the grid to be view models for the dialog - that is, the view model objects have properties implemented for both display in the grid and modification in the dialog window. On the other hand, if all the grid is doing is displaying data from the model, there may be no need for an intermediary object.
Note 2: Having the command create a WPF window violates a central MVVM design principle, which is that view models shouldn't create WPF objects. The reason for this principle is pretty simple: you can't build an automated unit test for this command, since it's just going to throw up a dialog and wait. There are all kinds of different approaches to this - see, for instance, this question, and Josh Smith's blog post on the Mediator pattern - and all of them involve delegating the creation and display of the actual dialog window to a separate service that can be mocked out for unit testing. If you don't want to choose one of those approaches up front, you can retrofit one into your application once you get this thing working.
The idea here is that you should attach an object which is slightly different from your business models. In your case it won't UserInfo (or whatever you have for users in grid). It will be some other class, more suitable for editing. In MVVM this class will be a ViewModel. This class will have some differences comparing to your regular user class, for example it may have some properties nullable (when you haven't set them yet). Also this class will handle validation. You should instantiate this class at the same time you're creating an editor window and put instance of this class into Window.DataContext.
Hmm, there is a lot in this question but I just created a screen with three data grids (I am using Telerik in this case) and under each datagrid is a button to add to the grid. No the window with the three datagrids has it's own view model. and each of the "pop up's" has it's own viewmodel, in this case all of these are user controls and I just create a new window and set window.content and call show dialog.
Communication is facilitated via "events" - not the standard events you are used to in .NET but in this case I am using Prism and it's CompositePresentationEvent class. When the user is done creating their new object they click add and I fire off this event with the "payload" being the object they created. The main window with the three grids listens for that event and has a method to handle it, in this case adds it to the ObservableCollection which is what I bind the grids to.
If I were you I would look into the various frameworks that are out there, Prism, MVVM light etc... Again, your question seemed rather broad, I tried to give an overview but I didn't go into detail, if you look into some sort of framework I think it will clear up a lot of these details for you.
When the users hit Add New, create a new blank copy of your object, and set the datacontext to that new object.
Set some kind of flag to identify that it is a New object. This can be the Id being NULL, 0, -1, etc or an ObjectState property set to New. That way all your validation rules apply, and once the user hits save you know to INSERT instead of UPDATE
I'm building a simple financial record-keeping application. The main window view model holds a list of Accounts. The view shows this list (in a ListView) along with a panel showing details about the currently selected Account.
At first, I bound the details panel and ListView's SelectedItem to the same property (of type Account) on the view model. However, I quickly realized that the details panel needed to be bound to an AccountViewModel, not directly to an instance of Account.
There are several ways to providing this AccountViewModel:
Bind the details panel to a separate property on the view model. When ListView's SelectedItem changes, the view model should create and set this new property to an instance of AccountViewModel that is associated with the selected Account.
Give the main view model a list of AccountViewModels instead of an Accounts list. Both the ListView listing all accounts and the details panel could then be bound to the same property on the main view model.
Have one AccountViewModel, changing the Account it references with each change to ListView's SelectedItem property.
Are there other options? Which choice do you recommend?
Thank you,
Ben
This is what I do:
Give the main view model a list of
AccountViewModels instead of an
Accounts list.
This will serve you well in many ways. I always find that eventually, for one reason or another, I need to augment my Models in some way to support a View, so these days I just start out by creating ViewModels.
The way you can tell that this is going to be a better option is that it involves less code. Less code always equals less bugs, in my opinion.
i like this option
Bind the details panel to a separate
property on the view model. When
ListView's SelectedItem changes, the
view model should create and set this
new property to an instance of
AccountViewModel that is associated
with the selected Account.
then you can bind the selected item to the view model and the details pane as well. this can be tested independently of the view. when you create your list of accounts you can also create a list of account view models, so when you change selection you are not having to create anything its all sitting there. this way your viewmodel is comprehensive, representing the whole screen not just floating bits of viewModel.
So far, the idea I like best is #3 from the original post for two reaons:
It has a 1 view to 1 view model correspondence, which I think best fits the M-V-VM pattern.
Since the account view model is told when to change to display details of a different account, it can ask the user if he wants unsaved edits to be saved before changing to display the new account (etc.).