Binding to a Model that Contains a Collection/List - wpf

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.).

Related

Binding a WPF read only view to a viewmodel

I have a WPF application designed using MVVM. I have a view which will always be read only. It is a product result view. So a user will searh for a product in someother view and the search result will be displayed. So when the user double clicks a particular result record, the product details view will be opened which is a read only view. When the user double click another product record in the search result, the sam product details view will be refreshed(Not instantiated) with the new details data. I am thinking of binding the product details view to the viewmodel using OneWayToSource binding mode. Is this good?I believe this will result in reduced memory footprint.Pls confirm? Also, still, do i have to implement INotifyPropertyChanged in the viewmodel properties even the view is a readonly view?
I doubt the binding mode will make any difference to memory footprint, just extra stuff to type in. So long as you use read-only controls and textblocks and the like then keep it simple.
As for the NotifyPropertyChanged: No, it isn't required. However, if you have an Edit view sharing the same view model then it can be beneficial since then edits to those properties will automatically propogate to an open read-only view. Same goes if there are any commands or such that may result in a value of the viewmodel changing, without INotifyPropertyChanged, the view will not refresh those changes. If those types of refreshes aren't needed, then neither is INotifyPropertyChanged.

Prism - strategy for removing newly added record from master view

I have a typical master-detail scenario. User can click "Add New" in the master view and enter the details in the detail view. So for example lets say I have list of ObservableCollection of Product. When the user clicks "Add New", I add a new Product record to the ObservableCollection and then open a detail view for adding the Product details. This works well if the user does save the product. However if the user decides to cancel the addition of new Product, how do I remove the same from the ObservableCollection of Product in the master view. Right now I could think of two ways, first to pass the reference of ObservableCollection to the Details view, and second, use events to notify master view about the new Product record deletion. What do you suggest ? Also, if there is better way to handle this in prism specifically, please let me know.
regards,
Nirvan.
Passing a reference to the ObservableCollection to the details view is a no-no - it should only know about the record it is bound to.
You have not specified the UI you have in place for this, there can be a couple of ways to do this that may be better suited for your design. However one reasonably agnostic way to do it is to use the EventAggregator to publish the event which the master view can subscribe to. It is up to the master view how to deal with that event, different views can respond in different ways. In this particular case the master view can check the currently selected item, and if it is new (i.e. hasn't been saved, doesn't have key pieces of info like an ID) then it can simply remove it from the collection and discard it.

How to assign context and refresh it in Entity Framework?

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.

Building a data entry form in wpf

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

MVVM WPF ViewModels for Adding New Entity

My concept for MVVM in WPF is that we have a ViewModel for every Model in your application. This means that if we have Customer class (entity) then we will have CustomerViewModel. The CustomerViewModel will have all the properties which are necessary to represent a customer. The CustomerView usercontrol will be responsible for creating the UI for the Customer model.
Now, let's say that we are adding a new customer. So, we have a form which consists of FirstName, LastName etc. Do we need a ViewModel for this scenario. I mean all I have to do is to take all the input values from TextBox and create a Customer object and then save it to the database. Why should I bother creating a ViewModel for this scenario?
First of all, that is not the main purpose of MVVM, to "mirror" everything. The View should provide the means for a user input, and certainly not process calls to any of the database layers. The ViewModel should be a GUI-agnostic application backbone, and it definetly should handle the creating of customers.
That said, what you should do, is have a ViewModel which represents a workspace for handling customers, and not just a customer ViewModel. If you really want to save on a few objects being created, add to that workspace the possibility to create and add a new customer (not CustomerViewModel). That way, you can have a View of the workspace which has elements for each relevant/required property of the customer, and by invoking some command added to that workspace ViewModel, you could get the current values filled in those (data bound to ViewModel) View elements directly to the customer model.
Consider if you could probably drop the specific customer (and other Model) ViewModels if you refactor things a bit, it would be good practice to keep things from adhering blindly to a certain pattern without explicit cause.
Let's pretend for a second that there is no business model. The only thing you have is a view. If you were to model just that view, without any knowledge of what the data means elsewhere in the system, that is a ViewModel.
The goal of a ViewModel is to, well, model the view it backs. This is a different goal than modeling the idea of a customer in your business domain. To say you will have have one ViewModel per business entity, then, is to say you will have one view per business entity, which leads to run-of-the-mill data-focused UI.
In your particular case, think about the customer edit view. It has fields that correspond to a customer's properties, and thus seems like a natural fit for binding to a customer directly. However, where on the customer object is the "Submit" action modeled? Where is the "Cancel" action modeled? Where is it modeled that field X is an enumerated value selected from a list?
How about the password? If persisted as a binary hashed value, does the view know how to hash its text? What if the system has password strength requirements?
The ViewModel is the mortar between the business model and the UI. It takes concerns from one and translates them into terms of the other. It is the point at which all the above issues are addressed. To say a ViewModel isn't necessary is to ignore its necessity.
You don't need to have a separate ViewModel for Add, you only need a single ViewModel which should do Edit and Add scenarios. If you can delete the record from the edit page than that ViewModel should also have the ability to delete. Your ViewModel should reflect the functionality your View exposes regardless of data.
I think you should reconsider having a single ViewModel for each model. I like to think of ViewModels as normalizing behavior inserted of data. By having a ViewModel for each Model class you will run into architecture issues sooner or later. I look at the application from top down overview, what is my UI trying to accomplish and from there I will get to the ViewModel and eventually I will get to my DataFactory and how the ViewModel maps down to data is almost always not 1 to 1 except for the most simplistic Views. If you try to map 1 to 1 you will have bad UI or your data will not be normalized very well.
The Stack we have here is:
View
ViewModel (Controls everything the user can do in the view, wraps properties from our POCO's)
DataFactory (Maps our POCO's to Entity Framework objects and CRUD)
POCO's (Business Logic, all rules and validation)
Entity Framework (Model, Data Access)
One note here is that ViewModel contains properties from multiple POCO's!
We inject the DataFactory through StructureMap and Unit test with xUnit along with Moq.
To answer you second question I would create a separate view only view to drop in as a user control. But you should still have a CRUD ViewModel in you app that encapsulate all that functionality in a user friendly way.
Thanks.
One reason for this VM abstraction is for testability. Another reason why you want a ViewModel is because it's basically a Data Transfer Object that might be a combination of fields from multiple models in a single container that is more relevant to your current view. Yet another reason to have VM is to take advantage of WPF two ways binding capabilities.
Using your regular model (plain POCO), you can update the View when your model change, but since your model does not implement dependency properties (most likely), you won't be able to take advantage of updating your model when the value in WPF control changes. Which mean you have to manual add a handler and do the copy this value from this control back to the model kind of thing.

Resources