I want to write a ViewModel that always knows the current state of some read-only dependency properties from the View.
Specifically, my GUI contains a FlowDocumentPageViewer, which displays one page at a time from a FlowDocument. FlowDocumentPageViewer exposes two read-only dependency properties called CanGoToPreviousPage and CanGoToNextPage. I want my ViewModel to always know the values of these two View properties.
I figured I could do this with a OneWayToSource databinding:
<FlowDocumentPageViewer
CanGoToNextPage="{Binding NextPageAvailable, Mode=OneWayToSource}" ...>
If this was allowed, it would be perfect: whenever the FlowDocumentPageViewer’s CanGoToNextPage property changed, the new value would get pushed down into the ViewModel’s NextPageAvailable property, which is exactly what I want.
Unfortunately, this doesn’t compile: I get an error saying ‘CanGoToPreviousPage’ property is read-only and cannot be set from markup. Apparently read-only properties don’t support any kind of databinding, not even databinding that’s read-only with respect to that property.
I could make my ViewModel’s properties be DependencyProperties, and make a OneWay binding going the other way, but I’m not crazy about the separation-of-concerns violation (ViewModel would need a reference to the View, which MVVM databinding is supposed to avoid).
FlowDocumentPageViewer doesn’t expose a CanGoToNextPageChanged event, and I don’t know of any good way to get change notifications from a DependencyProperty, short of creating another DependencyProperty to bind it to, which seems like overkill here.
How can I keep my ViewModel informed of changes to the view’s read-only properties?
Yes, I’ve done this in the past with the
ActualWidthandActualHeightproperties, both of which are read-only. I created an attached behavior that hasObservedWidthandObservedHeightattached properties. It also has anObserveproperty that is used to do the initial hook-up. Usage looks like this:So the view model has
WidthandHeightproperties that are always in sync with theObservedWidthandObservedHeightattached properties. TheObserveproperty simply attaches to theSizeChangedevent of theFrameworkElement. In the handle, it updates itsObservedWidthandObservedHeightproperties. Ergo, theWidthandHeightof the view model is always in sync with theActualWidthandActualHeightof theUserControl.Perhaps not the perfect solution (I agree – read-only DPs should support
OneWayToSourcebindings), but it works and it upholds the MVVM pattern. Obviously, theObservedWidthandObservedHeightDPs are not read-only.UPDATE: here’s code that implements the functionality described above: