Reputation: 5519
I'm currently trying to wrap my ahead around the MVVM-Pattern
. In addition I'm using PRISM
for IoC-support etc. But there is one thing (among others) in particular, that I'm not comfortable with the way I'm doing it, because it seems a bit strange to me, so maybe I didn't get it right.
Let's say I want to make a ListView
that displays part of a database schema. So on the "top-level" I would have one element per database. Within these elements I want to show the tables in that database and within that, the column names of that table.
The way I'm doing this now, is to create 3 view models (+1 Base-ViewModel for the view hosting the ListView
). One for each "layer" of the ListView
. So I'd have f.e. a DatabaseViewViewModel
, a DatabaseTableViewViewModel
and a DatabaseTableColumnViewViewModel
(names are not too hot here).
So the Base-ViewModel has an ObservableCollection
of DatabaseViewViewModel
s, the DatabaseViewViewModel
has an ObservableCollection
of DatabaseTableViewViewModel
s and so on.
So obviously those view models need some configuration data (the DatabaseTableViewViewModel
f.e. needs to know it's database). In my opinion an object should be completly initialized after creation, so I'd like to pass that data in the constructor. Of course, that makes it impossible to resolve those view models from an IoC container. But I "have" to resolve it, since they have some dependencies that need to be resolved (f.e. an IEventAggregator
).
As far as I've read, the (or at least one) way to handle this, is to use Factories
to create the view models, but I'm not quite happy with that layout. It seems a bit "oversized".
So I wanted to ask you, if I have maybe overlooked something.
Is my view model design valid? Or how would you design your view models for this kind of "hierarchical" ListView
?
Edit: For clearification: The reason I'm creating those 3 different view models is, that I think it gets a little messy (in fact I'm having trouble to come up with an idea of how to implement that at all off the top of my head) when you try to expose properties of objects further down the hierarchy (f.e. the column names) for databinding.
Of course I could use dependency properties or implement the INotifyPropertyChanged
in my model classes - and that might in fact be a good way to go for a new project - but let's assume you have a model, that can't be easily modified.
Edit2: Regarding Sheridan's comment on the weird view model classes, that's because in the app I'm developing, the database schema IS my data. I'm not working on the actual data in the database. (I'm developing a MySQL Management Agent for Microsoft's Forefront Identy Manager. That management agent needs to know the schema of the database (relationships etc.), which currently gets read in from an XML file. So I'm building a UI to comfortable create said XML file. If I was working with the actual data in the database, the view models would most certainly look completely different.
Upvotes: 0
Views: 710
Reputation: 69959
I think that you might be slightly on the wrong path here... in my opinion, it is far easier to implement the INotifyPropertyChanged
interface directly in your data objects, rather than having a separate view model for each of them. Your .NET classes won't necessarily match your database schema... think about Object Oriented Programming:
Your database might have Company
, Person
and Address
tables, but in .NET, your Company
class might contain a collection property of type Person
and each Person
class could have a property of type Address
... so now we are building hierarchical data classes... just perfect to be displayed in hierarchical controls in the UI.
Now continuing this example into the view model level, you would just need to provide a collection of the Company
data types to bind to an ItemsSource
control property and maybe a single Company
property to bind to a SelectedItem
control property.
One thing that rang alarm bells for me while reading your question was regarding your DatabaseViewModel
... basically no, no, no. We should never see a view model with this name (in a large scale application at least). The data comes via the model and not the view model... and we don't match our view models to our database tables... just use basic data type classes for that.
Think of it like this... my data type classes hold all properties for each of my database table columns, but are connected in a more 3D, or hierarchical manner. I generally have one .NET class for each table, but weak entity, or joining tables are usually implemented in .NET as one class having a property of the type of another class in them.
The model (database access) class fills these data type classes from calls to the database and pass them to the view model classes. My view model classes are simply collections of all of the properties required in each particular view and most of these have the data type classes as their type. My view models also have methods that provide the functionality for the views.
I personally feel that using MVVM goes hand in hand with WPF and wouldn't dream of using WPF without it (except for the smallest applications). I feel that you might benefit from some more reading about MVVM, although maybe the answers you receive here might be enough.
Upvotes: 1
Reputation: 3297
As a rule of thumb, for those dependencies that are known at compile time I use the IoC container to configure them and inject them in to the relevant classes. For those dependencies that require runtime information (for example the selection of a database) I inject a statically configured factory that enables me to create those objects at runtime.
To this end I do not think that that the use of Factories is "oversized".
The important thing is to model your view models in the correct way, which you seem to be doing. Databases contain tables - consequently your view models should (and does) reflect this. I think you are going down the right path!
Upvotes: 1
Reputation: 18580
First of all I dont think you need three viewmodels. These shoud be "Models". DataBaseModel will be the parent model containing list of TableModel which in turn contains ColumnModel list.
Then you need just one ViewModel which will have List of DataBaseModel and this viewmodel will serve as Datacontext for your view. The viewmodel will have default constructor so it can be resolved. In order to initialize the DatabaseModel, use configuration to provide connection strings to intialize it.
For hierarchical structure use TreeView with HierarchicalDataTemplates to show the hierarchy.
Upvotes: 0