Click here to Skip to main content
15,887,898 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Initially when I first submitted this question, it was indicated as being too long. I confess, it spans a couple related questions. I’m struggling with overall application structure and where to locate properties.

I’ve been working with C# and WinForms apps for > 5 years, and decided to start learning WPF and MVVM for a new project. It’s proven rewarding, however seems people are torn in several directions for some concepts; making it hard to research and come up good direction.

I should note, I’m doing this in C# 6.0, .NET 4.5.2, and without the use of frameworks such as Prism or MvvmLight. I’d rather learn the basics first, before applying some magic.

I’ll outline my project, to help illustrate the questions.

The application I’m building, allows viewing only of technical support tickets from an SQL2000 database. I only query the database, never writing to it (we have a separate app for that). I have no control over the database, and no way to influence moving to something newer. Additionally, some of the tables are not very normalized; duplicating data, etc. Unfortunately I can’t use Entity Framework without jumping through hoops. I query the database, and populate my custom entities. While there’s many tables in the database, there are four main ones I’m using: Ticket, Event, Escalation, and Rma. The Ticket table has a one-to-many relationship with the Event, Escalation, and Rma tables; where one Ticket can relate to zero or more Events, Escalations, or RMAs. I query the database for a set of tickets. When the user selects a specific ticket from the list, it queries the database for the rest of the ticket information so I can populate the Events, Escalations, and RMAs.

Views:
MainWindow.xaml (Window) – Menu, TicketsView, StatusBar
TicketsView.xaml (UserControl) – TicketsGroupBox (text bound to TicketCollectionName), TicketsDataGrid, TicketView
TicketView.xaml (UserControl) – TicketGroupBox, EventsGroupBox, EventsDataGrid, EscalationsGroupBox, EscalationsDataGrid, RmasGroupBox, RmasDataGrid

ViewModels:
MainWindowViewModel – TicketsViewModel, TicketsRepository, Menu commands, StatusText
TicketsViewModel – TicketsRepository (passed in constructor when created), TicketCollectionName, ObservableCollection<Ticket>, SelectedTicket (creates TicketViewModel from Ticket object passed by TicketsView.TicketsDataGrid.SelectedItem)
TicketViewModel – Ticket, ObservableCollection<Event>, ObservableCollection<Escalation>, ObservableCollection<Rma>

Models:
Ticket – Ticket table properties, List<Event>, List<Escalation>, List<Rma>
Event – Event table properties
Escalation – Escalation properties
Rma – Rma table properties

Additional:
TicketRepository class – Interacts with database, populating list of Tickets objects.

Hopefully the above gives a picture of the relationship between the MVVM objects, rough idea what the app structure.

First problem I ran into is that I need calculation/summary/total properties to be presented in the DataGrids. One would think you should just include those properties in the Model, however the more popular opinion I’ve read, is to never include that logic in the Model. Many people put those in the ViewModels; which can make sense. So then instead of having TicketsViewModel.ObservableCollection<Ticket>, I’d have TicketsViewModel.ObservableCollection<TicketViewModel>. Anytime the SelectedItem changed, I’d already have the TicketViewModel ready to go; and wouldn’t need to create it. The complication here is, what if I need calculation/summary/total properties in the other three DataGrids that don’t have separate View/UserControls, i.e. EventsDataGrid, EscalationsDataGrid, and RmasDataGrid? Do I still create those in ViewModels; or do I create those in some other sort of wrapper class to the Model?

If I follow the logic above, then the structure seems to get complicated fast; having to maintain a separate hierarchy of Model and ViewModel objects. If it is the right approach, I’m not sure where things should be and when/where I’d load them. Kind of seems like I’d be duplicating effort, but can’t see how else to do it if I need those calculation/total properties. Does that mean I need to create a ViewModel every time I need them? Or am I going about this the wrong way?

Thanks for any guidance; I’d greatly appreciate it.

What I have tried:

I've tried the structure I outlined above, but then started creating ViewModels as I discuss toward the end.
Posted
Comments
J. Calhoun 15-Jul-16 12:30pm    
This is hard to troubleshoot because I can't see how you are using these things so I am not sure the context of calculation, but judging that you are putting these properties in the view model then I am guessing that summary/total is something like the summary or total of the entire collection of RMAs/Escalations/Events.

Also, are these grids in separate views? So you are saying in each view model you would need something like Calculation {get; set;}

The way you can keep track of all of this is the observer pattern which Sunil Kumar explains here Observer Pattern in .NET[^] also Islam ElDemery has a good implementation Design Patterns - Observer Pattern[^] So each view model that needs to know about the OnChanged event could just register to that event so they will all update when needed.

Another thing I don't understand is Tickets.ViewModel.ObservableCollection<ticketsviewmodel> so you have multiple instances of the same View Model? Doesn't that break your bindings? There should only ever be 1 TicketsViewModel therefore shouldn't be a collection.
bnmc 28-Jul-16 10:42am    
Thanks for the reply J. Calhoun; must have missed it.

I think I figured out a good direction to head in, due to replies to my other posted question. The base question here is, should I include the calculation properties in the Model objects, or a wrapper for those Model objects, such as a ViewModel.

I've decided to only bind directly to the ViewModels, so I only create the calculation properties in the ViewModels. But since the ViewModel is acting as a wrapper, and that I want to include totals in the DataGrid in the View, I need to have ObservableCollections of things like TicketsViewModel.ObservableCollection<ticketviewmodel>. Then when a user selects one of those items, the SelectedItem changes which is bound to TicketsViewModel.SelectedTicketViewModel. In TicketsView, there is a UserControl which has it's DataContext set to SelectedTicketViewModel; so it updates every time the user clicks on a different item. Seemed the easiest/best way to do it.

I will look at Observer Pattern again as I think it could make other things a little easier.

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900