microsoft / microsoft-ui-xaml

Windows UI Library: the latest Windows 10 native controls and Fluent styles for your applications
MIT License
6.29k stars 675 forks source link

Cannot determine when a control can release resources when NavigationCacheMode is Required #3308

Open phraemer opened 4 years ago

phraemer commented 4 years ago

Consider the case where you have a templated custom control, class CoolThing : Control.

CoolThing acquires some expensive resources when IFrameworkElement.Loaded is invoked and releases them in IFrameworkElement.Unloaded.

However, the acquisition and release of these resources is a bit slow. It would be nice to set NavigationCacheMode="Required" in the Page containing a CoolThing and only unload those resources when we know we really don't need them any longer. However, there is no event CoolThing can subscribe to in order to be informed when the Page is being ejected from the cache and CoolThing can now release it's resources.

Or is there? Perhaps it's just not obvious.

There is also no property that informs CoolThing that even though Unloaded is invoked that the control will not be destructed and Loaded may invoke again.

Is this just the way things are or is there something I've missed?

StephenLPeters commented 4 years ago

@chrisglein and @MikeHillberg any ideas?

phraemer commented 3 years ago

Could really do with some insight here so I can help a customer out.

phraemer commented 3 years ago

@gabrielbunselmeyer you might want to subscribe to this one too

MikeHillberg commented 3 years ago

I don't think there's any API that a control can listen to to determine it's in a Frame and no longer cached. You will get destructed/GC'd though, are you trying to close the timing window on that?

Side note, the Loaded and Unloaded events have an ordering issue that gets in the way as described here. More info at https://github.com/microsoft/microsoft-ui-xaml/issues/1900.

ghost commented 3 years ago

This issue has been automatically marked as stale because it has been marked as requiring author feedback but has not had any activity for 7 days. It will be closed if no further activity occurs within 7 days of this comment.

phraemer commented 3 years ago

@MikeHillberg I'm no longer working at the organisation where this is relevant but @gabrielbunselmeyer is. Nevertheless, if I remember correctly, if the process ends then the destructor will not be called? Perhaps, Gabriel can confirm this.

gabrielbunselmeyer commented 3 years ago

if the process ends then the destructor will not be called?

That's right, the destructor for CoolThing didn't get called at all, even when the page is taken out of the cache if you set a CacheSize, which means we don't have a way of knowing when to release unmanaged resources for those pages. Ie having 3 pages where caching is enabled, but a CacheSize of 1.

Also of note is Pages with a Required cache mode are cached regardless of the CacheSize value, and do not count against the CacheSize total, which we may or may not have missed back then 🙈

I'm seeing consistent behavior now, with the constructor being called as expected when the caching is set to Enabled. I'll need to do some digging as it's been a while since we last worked on navigation.

There is also no property that informs CoolThing that even though Unloaded is invoked that the control will not be destructed and Loaded may invoke again.

I think this is still a valid concern though. It'd be ideal for the Unloaded method to somehow know caching is enabled and not having to depend fully on the garbage collector for removing the unmanaged resources, if I'm understanding the OP & remembering right. Is that possible in any way at the moment?

The loaded and unloaded ordering issue is very relevant to our case as well, and how our control interacts with navigation. Thanks for sharing it! @MikeHillberg

chrisglein commented 3 years ago

Question has been answered I believe by Mike. There's not a way to do this now. Reframing this as a feature request (that it'd be good to be able to get events for this). Let me know if I'm off-base in framing it that way.