Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF: when does binding actually occur?

Tags:

wpf

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

like image 805
Andrew Stephens Avatar asked Jun 22 '26 15:06

Andrew Stephens


1 Answers

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.

like image 97
Abe Heidebrecht Avatar answered Jun 24 '26 18:06

Abe Heidebrecht



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!