Andrew Stephens
Andrew Stephens

Reputation: 10193

WPF: when does binding actually occur?

My MVVM app has a number of views that inherit from a base user control, which exposes an "ID" property. In the XAML this is bound to an ID property on the view's underlying view model, simply:

Id="{Binding Path=Id}"

The view model implements INotifyPropertyChanged, and its ID is set in the constructor. The ID is used to uniquely identify each view/view model, and is primarily used by a "desktop manager" to manage the user controls within the main window, rather like an MDI app. When my app starts I instantiate the various view models and their views, and assign the view models to the views' DataContext. I then pass the views to the desktop manager which places them on its canvas, positions them, etc.

The problem I have is that the view's ID is still null at this point, and only seems to get bound to the data context some time later (when the UI is rendered perhaps?). I have tried forcing the binding like this, but it doesn't help:-

var bindingExpression = widget.GetBindingExpression(DesktopElement.IdProperty);
bindingExpression.UpdateTarget();

It's not the end of the world, as I can pass the desktop manager my view and the ID from the view model, but it feels a little hacky. I was curious to know at what point in the control/window lifecycle the binding occurs, and whether there was some other way to force the binding to happen?

Thanks in advance Andy

Upvotes: 3

Views: 1295

Answers (2)

Dan Bryant
Dan Bryant

Reputation: 27495

My suggestion would be to have an interface that your View Models implement, which exposes the Id property. You can then have your Desktop Manager grab the Id from the DataContext by casting it to the appropriate interface. This is likely a cleaner separation of responsibilities, as your Desktop Manager should probably know as little about the concrete View as possible (for the sake of testability.)

Upvotes: 0

Abe Heidebrecht
Abe Heidebrecht

Reputation: 30498

In order to understand how bindings are transferred, you need to understand the Dispatcher. Basically, it is a priority queue. Things like layout, bindings, rendering, input, etc. are placed in the queue at different priorities.

Now, from the sound of it, you never yield execution back to the Dispatcher. This means that Binding values can't transfer (when you manually call UpdateTarget you are just scheduling this on the Dispatcher). So, in short, you need to let the Dispatcher execute the queued operations before you finish initializing.

The easiest way to do this is to call BeginInvoke at a lower DispatcherPriority on a method to finish initialization. Because of the nature of how the layout system works, it can be tricky sometimes to pick the right priority, but you'll probably be okay if you go with DispatcherPriority.Loaded.

Upvotes: 1

Related Questions