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.