Best way to bind WCF DomainService data to a TreeView in Silverlight? - silverlight

I've got a database structure similar to this:
Items
ID
Name
ParentItemFK (tasks & notes can have any item as a parent; categories can only have other categories as a parent)
CategoryFK
TaskFK
NoteFK
Categories
ID
Description (optional)
Tasks
ID
FullDescription
IsComplete
Notes
ID
FullText
The items are to be displayed in a TreeView. An item can be either a category, task, or note (so one and only one of the FK columns are filled in).
I'd like to display all items in a TreeView. I am using a DomainService with WCF to get the data from the back-end, for display in Silverlight.
I could programmatically build objects to be displayed in the TreeView (i.e. make an object such as ItemNode, with child ItemNodes for each sub-item). This would probably work alright, but when the data that the DomainService has is refreshed, I think the whole list of ItemNodes would have to be rebuilt (which could happen often).
I'm using entity framework underneath the DomainService, if that matters.
Is there a better way to do this??
Thanks!

I did something similar to this and I created a custom object which represented my hierarchy. Then I created a helper class to recurse through the custom object and create Tree nodes to bind to the TreeView.
I also used the Hierarchy SQL Datatype to represent my Hierarchy in the database.
Since your using Entity framework, I'm thinking your best bet is to just create some TreeNode class which will take in your entities and then recurse through them and spit back out a Hierarchy of TreeNodes which you can then bind to the TreeView.
Also, you will want to put the unique identifier for that entity in the TreeNode.Value so that when a user interacts with a node, you will be able to easily modify the entity which represents the TreeNode. So, create another class which will recurse through your entities and get a reference to that entity based on its identifier.
hth

Related

Common model among multiple views

New to WPF. I have a Product model that is an L2S entity. I am creating an application in WPF to edit the product information to potentially replace an old Windows forms app I have. the application has a tab control with a number of tabs on it, such as Packaging, Marketing, Photos, Construction, etc.
My question is how do I structure this in a MVVM system. Do I have a separate view for each tab, each with it's own view model relating to it's particular subset of the Product model? Or do I have a single view with the tab control and all of the fields and a single view model to encompass the model in it's entirety? Or am I going about it completely wrong?
I feel like the first option is the way to go, but then I am also unsure of how to share the same model across multiple view models. Can anyone shed some light on this for me?
--Edit--
Examples of data on the pages:
Marketing has several text fields, and a few subset entity collections such as features, applications, and cross references.
Photos handles a collection of Photos for the product
Packaging and Construction are each a large collection of text fields/combos/checkboxes related to their respective information in the Product
With this minimum of info you've provided I would suggest following solution:
Main ProductView view
Separate View for the each tab
Main container ViewModel: ProductViewModel
For complex tabs separate view model as well. For instance you would have a separate PackagingViewModel so ProductViewModel should expose public PackagingViewModel Packaging property
ProductViewModel should accept all model-related stuff (perhaps some services, model entity, etc) and then initialize all other child view models.

Is it possible to have TreeView load node on demand with EntityFramework & MVVM?

So I have a header table, Client, and each client have some customer.
I am using entity framework to query the data.
When the TreeView display, it will only show Clients, then until user Expands the Client node, it will query its Customers.
Is it possible to do this in MVVM + Linq?
I could do something dynamic, like click on first node and fire event for query, dynamic add tree item etc.
But I want to know if that's possible to do it in easier way?
Like by take advantage of lazy loading with Linq, databinding etc? Is it possible?
Is it possible, absolutely, but how you do it depends on a lot of different factors which are specific to your project.
What I would do is create a custom TreeViewItem class that takes your entity (probably via the constructor) and then when it's Items property is called, it could call your entity's Clients navigation property. If you have lazy loading properly configured, it would be here that the actual database query happened.
If you had 10 nodes, and the user only expanded node 2, then only that node's query would ever fire.

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.

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.

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