+1  A: 

The numbers you're seeing in your proof of concept are actually normal. They are the result of virtualization of rows inside the datagrid; when an item is scrolled out of view, the container row is re-used to display a newly entered item, thus keeping memory usage low with respect to the actual visual controls created and manipulated. Displaying another item means requerying the bound properties.

Normally I don't imagine this would be a problem; I've worked with pretty complicated business objects and displayed quite a lot of data in the datagrid without the kind of problems you're mentioning. I would suggest taking a look at any styles applied to the datagrid, as they may interfere with the virtualization of rows; also, property getters that take 2 milliseconds to execute aren't what I'd call fast :)

Edit: actually, avoiding the additional calls to the property getters would only be possible by disabling virtualization, which would create huge performance problems - both tons of wasted memory and abismal scroll performance with even a 'small' (thousands) amount of rows in the datagrid. However, these are about the only things I can say without more information. If at all possible, try to step through the code when the getters are called and determine more precisely the source and timing of the majority of calls. If the problems occur when scrolling, then your entities are indeed incredibly complex and I question the value of displaying them in a datagrid in this way.

Another edit: I re-read the question more carefully and I noticed you said 12 items?! I'm sorry but now I'm quite adamant in saying that the datagrid shouldn't be blamed for this, unless your objects have thousands of properties, all bound to columns in the datagrid, which I doubt is at all possible. Please inspect the rest of the code and styles and try to determine any potential problem areas we could advise you about... not sure what else to say. Also check that the entities don't raise NotifyPropertyChanged events unnecessarily, as this will cause a property re-query by the bound controls.

Alex Paven
We figured out the problem. In our actual implementation, the objects which are being bound are wrappers to DataRow objects. They rely on the DataTable.RowChanged event to handle NotifyPropertyChanged for them. It turns out when these Rows are scrolled in and out of view, the RowChanged event is fired several times. Disabling that event took our call total from 200k+ to about 50 or so. Thanks for the tip regarding NotifyPropertyChanged.
GWLlosa