I like to think of it this way:
Views, as you say, are dumb. Josh Smith, writer of the seminal and often linked MSDN article on MVVM, has said that views are "the clothes that data wears." Views never actually contain data or directly manipulate it, they are just bound to properties and commands of your viewmodels.
Models are objects that model the domain of your application, as in business objects. Is your application a music store? Perhaps your model objects will be artists, albums and songs. Is your application an org-chart browser? Perhaps your model objects will be managers and employees. These model objects are not related to any kind of visual rendering, and they aren't even directly related to the application you're putting them into - your model objects should make sense completely on their own as a family of objects that represent some kind of domain. The model layer also typically includes things like service accessors.
This brings us to Viewmodels. What are they? They are objects that model a GUI application, meaning they provide data and functionality to be used by views. They are what define the structure and behavior of the actual application you are building. For the model objects, the domain is whatever domain you choose (music store, org-chart browser, etc.), but for the viewmodel, the domain is a graphical application. Your viewmodels are going to encapsulate the behavior and the data of everything your application does. They are going to expose objects and lists as properties, as well as things like Commands. A command is just a behavior (at its simplest, a method call) wrapped up into an object that carries it around - this idea is important because views are driven by databinding, which attaches visual controls to objects. In MVVM, you don't give a button a Click handler method, you bind it to a command object (served up from a property in a viewmodel) that contains the functionality you want to run when you click it.
For me, the most confusing bits were the following:
- Even though the viewmodels are models of a graphical application, they don't directly reference or use visual concepts. For example, you don't want references to Windows controls in your ViewModels - those things go in the view. ViewModels simply expose data and behaviors to controls or other objects that will bind to them. For example - do you have a view with a ListBox in it? Your viewmodel is almost certainly going to have some kind of collection in it. Does your view have buttons? Your viewmodel is almost certainly going to have some commands in it.
- There are a few kinds of objects that could be considered "viewmodels". The simplest kind of viewmodel to understand is one that directly represents a control or a screen in a 1:1 relationship, as in "screen XYZ has a textbox, a listbox, and three buttons, so the viewmodel needs a string, a collection, and three commands." Another kind of object that fits in the viewmodel layer is a wrapper around a model object that gives it behavior and makes it more usable by a view - this is where you get into the concepts of "thick" and "thin" viewmodel layers. A "thin" viewmodel layer is a set of viewmodels that expose your model objects directly to the views, meaning the views end up binding directly to properties on the model objects. This can work for things like simple, read-only views, but what if you want to have behavior associated with each object? You don't want that in the model, because the model isn't related to the application, it's only related to your domain. You can put it in an object that wraps your model object and offers up more binding-friendly data and behaviors. This wrapper object is also considered a viewmodel, and having them results in a "thicker" viewmodel layer, where your views never end up directly binding to anything on a model class. Collections will contain viewmodels that wrap models instead of just containing models themselves.
The rabbit hole goes deeper - there are lots of idioms to figure out like ValueConverters that keep MVVM working, and there's a lot to apply when you start thinking about things like Blendability, testing, and how to pass data around in your app and ensure that each viewmodel has access to the behavior it needs (this is where dependency injection comes in), but hopefully the above is a good start. The key is to think about your visuals, your domain, and the structure and behavior of your actual application as three different things.