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?
I like Dmitry Tashkinov's solution! However it crashed my VS in design mode. That's why I added a line to OnSourceChanged method:
If anyone else is interested, I coded up an approximation of Kent's solution here:
Feel free to use it in your apps. It works well. (Thanks Kent!)
Here is another solution to this "bug" which I blogged about here:
OneWayToSource Binding for ReadOnly Dependency Property
It works by using two Dependency Properties, Listener and Mirror. Listener is bound OneWay to the TargetProperty and in the PropertyChangedCallback it updates the Mirror property which is bound OneWayToSource to whatever was specified in the Binding. I call it
PushBinding
and it can be set on any read-only Dependency Property like thisDownload Demo Project Here.
It contains source code and short sample usage, or visit my WPF blog if you're interested in the implementation details.
One last note, since .NET 4.0 we are even further away from built-in-support for this, since a OneWayToSource Binding reads the value back from the Source after it has updated it
I use a universal solution which works not only with ActualWidth and ActualHeight, but also with any data you can bind to at least in reading mode.
The markup looks like this, provided ViewportWidth and ViewportHeight are properties of the view model
Here is the source code for the custom elements
I think it can be done a bit simpler:
xaml:
cs:
Yes, I've done this in the past with the
ActualWidth
andActualHeight
properties, both of which are read-only. I created an attached behavior that hasObservedWidth
andObservedHeight
attached properties. It also has anObserve
property that is used to do the initial hook-up. Usage looks like this:So the view model has
Width
andHeight
properties that are always in sync with theObservedWidth
andObservedHeight
attached properties. TheObserve
property simply attaches to theSizeChanged
event of theFrameworkElement
. In the handle, it updates itsObservedWidth
andObservedHeight
properties. Ergo, theWidth
andHeight
of the view model is always in sync with theActualWidth
andActualHeight
of theUserControl
.Perhaps not the perfect solution (I agree - read-only DPs should support
OneWayToSource
bindings), but it works and it upholds the MVVM pattern. Obviously, theObservedWidth
andObservedHeight
DPs are not read-only.UPDATE: here's code that implements the functionality described above: