We have an issue where our user control is initialized based on what the user sets in XAML when utilizing our control. Currently we were using the 'Loaded' event to act on what the user had set or not.
However, the issue with using the Loaded event is another sibling of this control is using their loaded event to set something on ours, which isn't yet fully initialized since our Loaded event hasn't yet fired. (It's a UI race condition if you will.)
Again, we can't move our code to the constructor as the WPF system hasn't yet set the properties specified by the XAML of the consumer of our control. We can't use the Loaded event for the reasons stated above. Initialized doesn't seem to work either.
I've also looked into ISupportsInitialize, but that's where we would be batch-setting the control's properties, not something externally, so that doesn't seem to be a fit either.
Thoughts?
Update
I've since found out this is an anomaly specifically with UserControls. They handle initialization differently. You can find more details in my follow-up question here...
...but the short version is calling InitializeComponent in the constructor actually raises the Initialized event, but does so before the XAML-defined properties have actually been set. Comment it out and the properties are now set when Initialized fires, but of course your control's UI isn't loaded! Kinda frustrating actually.
Still looking for a solution. Code examples and more details can be found there.
[Copying my answer from my other question here.]
Awesomesausage! I figured it out!
Normally when you receive the
Initialized
event (or are inside theOnInitialized
override) you have access to XAML-set property values. However,UserControl
classes work a little differently as they depend onInitializeComponent
being called to hydrate the UI and set the related member variables, etc.The problem is that call is in the constructor, which in turn ends up calling
OnInitialized
(and thus raising theInitialized
event) but that happens way before the XAML-set properties have been applied, meaning you don’t have access to them yet, which I needed.One may think that's a good use for the
Loaded
event--to finish initialization based on those properties--but if you're performing additional initialization there, you're creating a potential race condition with your consumers in that if they subscribe to yourLoaded
event and get it before you, then in their handler try to access your control, they will be accessing an uninitialized control.Then something occurred to me... As I showed above, if you remove the
InitializeComponent
call from the constructor, theInitialized
event now works as you would expect, but of course your UI isn't hydrated yet since you haven't yet calledInitializeComponent
.So what would happen if you moved that call to the beginning of the
OnInitialized
override, before the call tobase.OnInitialized
, and thus before theInitialized
event was raised?Yep! That worked! :)
This way not only do you have the XAML-set properties, but you’d also have the UI fully loaded before anyone gets the
Initialized
event (let alone theLoaded
event), which is how theInitialized
event is supposed to be used.Below is the revised code...
InitializeComponent
call, but that just means you have to plan to move such name-based initialization betweenInitializeComponent
and that call tobase.OnInitialize
and things will work just fine.