I recognise this is a popular question but I couldn\'t find anything that answered it exactly, but I apologise if I\'ve missed something in my searches.
I\'m trying to c
I am pretty new to WPF, but here's my understanding.
When you update or create controls programatically, there is a non-obvious mechanism that is also firing (for a beginner like me anyway - although I've done windows message processing before, this caught me out...). Updates and creation of controls queue associated messages onto the UI dispatch queue, where the important point is that these will get processed at some point in the future. Certain properties depend on these messages being processed e.g. ActualWidth. The messages in this case cause the control to be rendered and then the properties associated with a rendered control to be updated.
It is not obvious when creating controls programatically that there is asynchronous message processing happening and that you have to wait for these messages to be processed before some of the properties will have been updated e.g. ActualWidth.
If you wait for existing messages to be processed before accessing ActualWidth, then it will have been updated:
//These operations will queue messages on dispatch queue
Label lb = new Label();
canvas.Children.Insert(0, lb);
//Queue this operation on dispatch queue
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
//Previous messages associated with creating and adding the control
//have been processed, so now this happens after instead of before...
double width = lb.RenderSize.Width;
width = lb.ActualWidth;
width = lb.Width;
}));
Update
In response to your comment. If you wish to add other code, you can organize your code as follows. The important bit is that the dispatcher call ensures that you wait until the controls have been rendered before your code that depends on them being rendered executes:
Label lb = new Label();
canvas.Children.Insert(0, lb);
Dispatcher.Invoke(DispatcherPriority.Render, new Action(() =>
{
//Synchronize on control rendering
}));
double width = lb.RenderSize.Width;
width = lb.ActualWidth;
width = lb.Width;
//Other code...