ViewModel -> Model interaction - wpf

Suppose I have a WPF/MVVM application for managing some hypothetical customers :).
Domain model contains an entity named Customer (represented as a POCO in code).
The main screen contains a grid, bound to a view model (CustomersViewModel) that loads its data from Repository< Customer>.
The main screen also allows to create new customers (and save it to the DB).
Suppose I need to implement 'add customer' use-case. The most obvious approach is as follows:
Present the user with a dialog window to be filled out with new customer data.
Handle 'Save' button click in the ViewModel.
Create customer (var new_customer = new Customer(..)) domain object using the data from the dialog (step 1).
Call Repository< Customer>.Save(new_customer) to save the new customer to the DB.
Reload CustomersViewModel with fresh data from the DB so that newly added customer is visible in the grid.
Personally I don't like this 'quick-and-dirty' way (because of need to reload the full list of customers from DB every time a new customer is added).
Can anyone suggest a better approach (that wouldn't require refreshing the customer list from the DB)??? I feel there gotta be some best practice for handling scenarios like that:) ).
Thanks in advance!

If the saving of the Customer is successful, why can't you just add that single Customer instance to your collection of customers? No need to re-load all customers unless the user explicitly refreshes the view (usually via a refresh button).

If you are loading the list in your view through a binding (to a list of customers) you can just add the new customer to that list and everything is alredy ;-)

I have a similar application where in the object is created in UI. I solve it by adding the object in VM and then syncing it with Model on click of Save button.
I am assuming you have a list of CustomerViewModel in CustomersViewModel to which the grid view is bound to. You can add a new CustomerViewModel object to the list in CustomersViewModel. While saving the ViewModel data back into the model, the model gets in sync with VM. No need to refresh VM back from Model unless somebody else apart from your app is changing the Model data.

You could create an ObservableCollection<Customer> and fill it with the customers from the database which you want to show in the View. When you add a new customer then add it to this collection as well as save it into the database. The CustomersView binds on the ObservableCollection and is updated automatically without the need to refresh the data from the database.
The BookLibrary sample application of the WPF Application Framework (WAF) shows how this can be done.

Related

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.

MVVM: Communication

I am working on a large MVVM application. I am using the MVVM light toolkit for this. The application is like a web browser with back and forward buttons. The main view is an user control. I laid the back and forward buttons in the main view user control. The main view in turn has user controls. The user controls change when the back and forward buttons are clicked. The main ViewModel keeps track of the current user control and loads the next one depending on the button click.
All these user controls are loaded depending on the selection(ID) made on the first step. Lets say, the main view is a search screen and we select a customer. The next screens would be Address, Billing, Requests, etc. These screens does not share any data. But the data is for the same customer.
So, is it a good practice, to store the customer ID in the main view? If I do this, I should have a UserControl_Loaded event bound to a command, where I would then request for Address and Billing Info.
Or I can move the buttons(back and forward buttons) to each user control instead of the main view, Pass the customer ID with the message which would load the next view.
Which is better?
A way I've done this sort of thing in the past is to implement a class that encapsulates the data context for the operation. All of the pages will be populated with (and update) properties of this class. The main view model creates an instance of this class and a collection of the page view models, providing each with the data context. It also handles navigation from page to page, implementing CurrentPage, NavigateForwardCommand, and NavigateBackwardCommand properties.
If the user backs up to page 1 and changes the customer ID, the data context is repopulated with the information appropriate to the new customer. Since all of the pages are looking at the same data context object, all of the subsequent pages will display the right information.
You'll need to implement property-change notification in the data context object, and handle PropertyChanged in the pages. When the CustomerID property changes in the data context object, the page view models will need to refresh properties that appear in their respective views.

CRUD in Winforms with linq-to-sql

I have a simple winforms application that I am connecting to my database with linq-to-sql.
I have generated the classes directly from the database, and I have a DataAccess class that wraps my datacontext and can give me whatever I need.
I have a view that uses an object datasource to populate a DataGridView and a set of related text fields, etc.. for my entity (lets call it EmployeeView)
The view loads all of the existing rows, and as I click through the grid, the fields update appropriately.
If I change fields, the changes will persist through record changes, but I am not sure how to save changes through my data access layer. How can I detect which records are dirty and need to be saved? How do I then save them? What is the best way to add new records? Delete records?
I can find a lot of resources online, but none with the kind of examples I need. Can anyone help me out with some of the basic patterns, or point me to a good place?
The most basic way to use LINQ-to-SQL classes, I believe, is to instantiate a list of them (let's use Employee, for example) to contain the Employees you wish to (potentially) edit. When the properties of those Employee objects are changed, the objects are automatically "dirtied", and a call to DataContext.SubmitChanges() will persist them.
List<Employee> employees = (from e in dataContext.Employees where e.Salary > 50000 select e).toList();
foreach(var employee in employees)
{
employee.CanAffordToyotaPrius = true;
}
dataContext.SubmitChanges();
If you're wrapping the DataContext and only altering the properties of the wrapper object with the DataGridView, you'll need some way to bubble those changes down into the underlying LINQ-to-SQL objects you used when you selected the data. For example, you could use the setter on your wrapper's properties to also set the underlying LtS object's properties.

Managing silverlight RIA services context lifetime

I'm working on a line-of-business silverlight application and I need a piece of advice concerning managing RIA services context lifetime.
Application - afer a few simplifications - is build of one big tab control. At the beginning there are 2 tabs: customer list and invoice list. These are plain datagrids with filtering/sorting and that sort of stuff.
User can add/edit customer or invoice selecting a row and double-clicking. Then the new tab is created with details of customer or invoice. User can open many tabs with different customers/invoices. After editing, user can save and close tab or just abandon edit and close.
The question is how to deal with data contexts.
Should I create one for customerlist and one for invoicelist and when user opens a new tab, I simply bind customer/invoive dataobject to control? This has an advantage that I dont need to refresh grids after saving changes. EDIT: This has some drawbacks. User can refresh grid - and what will happen to open detail tabs? User can also filter grid so some records being edited can be removed from datactx?
The other way is to create datacontext per tabitem. This is more safe but I need to handle refreshing grid(s).
I have no idea which method is better or maybe there is another alternative?
Use one ObservableCollection list in each case and it will automatically update the datagrids when items are changed.

Resources