diff --git a/src/Forms/Prism.Forms.Regions/Behaviors/RegionCleanupBehavior.cs b/src/Forms/Prism.Forms.Regions/Behaviors/RegionCleanupBehavior.cs new file mode 100644 index 0000000000..b30fd9605e --- /dev/null +++ b/src/Forms/Prism.Forms.Regions/Behaviors/RegionCleanupBehavior.cs @@ -0,0 +1,26 @@ +using System; +using Prism.Regions; +using Xamarin.Forms; + +namespace Prism.Behaviors +{ + internal class RegionCleanupBehavior : BehaviorBase + { + private WeakReference _regionReference; + + public RegionCleanupBehavior(IRegion region) + { + _regionReference = new WeakReference(region); + } + + public IRegion Region => _regionReference.TryGetTarget(out var target) ? target : null; + + protected override void OnDetachingFrom(Page bindable) + { + if (Region != null && Region.RegionManager.Regions.ContainsRegionWithName(Region.Name)) + { + Region.RegionManager.Regions.Remove(Region.Name); + } + } + } +} diff --git a/src/Forms/Prism.Forms.Regions/Extensions/ElementExtensions.cs b/src/Forms/Prism.Forms.Regions/Extensions/ElementExtensions.cs new file mode 100644 index 0000000000..b2f12266fa --- /dev/null +++ b/src/Forms/Prism.Forms.Regions/Extensions/ElementExtensions.cs @@ -0,0 +1,36 @@ +using Xamarin.Forms; + +namespace Prism.Extensions +{ + internal static class ElementExtensions + { + public static bool CheckForParentPage(this VisualElement visualElement) + { + return GetParentPage(visualElement) != null; + } + + public static Element GetRoot(this Element element) + { + switch(element.Parent) + { + case null: + return element; + default: + return GetRoot(element.Parent); + } + } + + public static Page GetParentPage(this Element visualElement) + { + switch(visualElement.Parent) + { + case Page page: + return page; + case null: + return null; + default: + return GetParentPage(visualElement.Parent); + } + } + } +} diff --git a/src/Forms/Prism.Forms.Regions/Regions/Behaviors/DelayedRegionCreationBehavior.cs b/src/Forms/Prism.Forms.Regions/Regions/Behaviors/DelayedRegionCreationBehavior.cs index ebd63c1f0b..380cc2d0f9 100644 --- a/src/Forms/Prism.Forms.Regions/Regions/Behaviors/DelayedRegionCreationBehavior.cs +++ b/src/Forms/Prism.Forms.Regions/Regions/Behaviors/DelayedRegionCreationBehavior.cs @@ -3,6 +3,8 @@ using System.Collections.ObjectModel; using System.ComponentModel; using System.Globalization; +using Prism.Behaviors; +using Prism.Extensions; using Prism.Properties; using Prism.Regions.Adapters; using Xamarin.Forms; @@ -26,7 +28,9 @@ public class DelayedRegionCreationBehavior private readonly RegionAdapterMappings _regionAdapterMappings; private readonly object _trackerLock = new object(); + private WeakReference _trackingElement; private WeakReference _elementWeakReference; + private WeakReference _pageWeakReference; private bool _regionCreated = false; /// @@ -59,6 +63,18 @@ public VisualElement TargetElement set => _elementWeakReference = new WeakReference(value); } + private Page ParentPage + { + get => _pageWeakReference != null ? _pageWeakReference.Target as Page : null; + set => _pageWeakReference = new WeakReference(value); + } + + private Element TrackingElement + { + get => _trackingElement != null ? _trackingElement.Target as Element : null; + set => _trackingElement = new WeakReference(value); + } + /// /// Start monitoring the and the to detect when the becomes /// part of the Visual Tree. When that happens, the Region will be created and the behavior will . @@ -66,6 +82,7 @@ public VisualElement TargetElement public void Attach() { RegionManagerAccessor.UpdatingRegions += OnUpdatingRegions; + TrackingElement = TargetElement; WireUpTargetElement(); } @@ -96,9 +113,7 @@ private void TryCreateRegion() return; } - // DependencyObject inherits from DispatcherObject which provides CheckAccess... - // TODO: Determine proper Forms replacement for CheckAccess... - //if (TargetElement.CheckAccess()) + if (TargetElement.CheckForParentPage()) { Detach(); @@ -109,6 +124,12 @@ private void TryCreateRegion() _regionCreated = true; } } + else + { + TrackingElement.PropertyChanged -= TargetElement_ParentChanged; + TrackingElement = TargetElement.GetRoot(); + TrackingElement.PropertyChanged += TargetElement_ParentChanged; + } } /// @@ -127,7 +148,8 @@ protected virtual IRegion CreateRegion(VisualElement targetElement, string regio // Build the region var regionAdapter = _regionAdapterMappings.GetMapping(targetElement.GetType()); var region = regionAdapter.Initialize(targetElement, regionName); - + var cleanupBehavior = new RegionCleanupBehavior(region); + TargetElement.GetParentPage().Behaviors.Add(cleanupBehavior); return region; } catch (Exception ex) @@ -138,7 +160,7 @@ protected virtual IRegion CreateRegion(VisualElement targetElement, string regio private void WireUpTargetElement() { - TargetElement.PropertyChanged += TargetElement_ParentChanged; + TrackingElement.PropertyChanged += TargetElement_ParentChanged; Track(); //if the element is a dependency object, and not a FrameworkElement, nothing is holding onto the reference after the DelayedRegionCreationBehavior @@ -148,7 +170,7 @@ private void WireUpTargetElement() private void UnWireTargetElement() { - TargetElement.PropertyChanged -= TargetElement_ParentChanged; + TrackingElement.PropertyChanged -= TargetElement_ParentChanged; Untrack(); }