From 3899b479fdf98c0c1b501810623021df6aa70590 Mon Sep 17 00:00:00 2001 From: Satoshi Nakamura Date: Fri, 7 Jun 2024 16:15:09 +0900 Subject: [PATCH] Fix DisconnectHandler --- README.md | 28 ++++++++++- .../Extensions/HandlerCleanUpHelper.cs | 37 +++++++++++++++ .../Handlers/SettingsViewHandler.Android.cs | 18 ++++++++ .../Handlers/SettingsViewHandler.iOS.cs | 46 ++++++++++--------- SettingsView/MauiAppBuilderExtension.cs | 18 ++++++++ .../Platforms/Android/Cells/CellBaseView.cs | 12 +++-- SettingsView/SettingsView.csproj | 2 +- SettingsView/SettingsViewConfiguration.cs | 8 ++++ 8 files changed, 141 insertions(+), 28 deletions(-) create mode 100644 SettingsView/Extensions/HandlerCleanUpHelper.cs create mode 100644 SettingsView/MauiAppBuilderExtension.cs create mode 100644 SettingsView/SettingsViewConfiguration.cs diff --git a/README.md b/README.md index 6d24a99..396a765 100644 --- a/README.md +++ b/README.md @@ -60,7 +60,20 @@ public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder - .UseMauiApp() + .UseMauiApp() + .UseSettingsView() // write this + ... +} +``` + +OR + +```cs +public static MauiApp CreateMauiApp() +{ + var builder = MauiApp.CreateBuilder(); + builder + .UseMauiApp() .ConfigureMauiHandlers(handlers => { handlers.AddSettingsViewHandler(); // write this @@ -69,6 +82,19 @@ public static MauiApp CreateMauiApp() } ``` +## Options + +MAUI has a fatal flaw in that the DisconnectHandler of the control is not automatically called. +(https://github.com/dotnet/maui/issues/18366) +SettingsView has an option to call DisconnectHandler on PageUnload to clean up. +To enable this, do the following. + +```cs +... +.UseSettingsView(true) +... +``` + ## How to write with xaml ```xml diff --git a/SettingsView/Extensions/HandlerCleanUpHelper.cs b/SettingsView/Extensions/HandlerCleanUpHelper.cs new file mode 100644 index 0000000..96591cb --- /dev/null +++ b/SettingsView/Extensions/HandlerCleanUpHelper.cs @@ -0,0 +1,37 @@ +using System; +using Microsoft.Maui.Handlers; + +namespace AiForms.Settings.Extensions; + +public static class HandlerCleanUpHelper +{ + public static void AddCleanUpEvent(this View view) + { + if (view is not Element element) + { + return; + } + + Page parentPage; + + void PageUnloaded(object sender, EventArgs e) + { + view.Handler?.DisconnectHandler(); + if (parentPage is not null) + { + parentPage.Unloaded -= PageUnloaded; + parentPage = null; + } + } + + foreach (var el in element.GetParentsPath()) + { + if (el is Page page) + { + parentPage = page; + page.Unloaded += PageUnloaded; + } + } + } +} + diff --git a/SettingsView/Handlers/SettingsViewHandler.Android.cs b/SettingsView/Handlers/SettingsViewHandler.Android.cs index cbfab5f..7b8f4f5 100644 --- a/SettingsView/Handlers/SettingsViewHandler.Android.cs +++ b/SettingsView/Handlers/SettingsViewHandler.Android.cs @@ -1,4 +1,5 @@ using System; +using AiForms.Settings.Extensions; using AiForms.Settings.Platforms.Droid; using Android.Views; using AndroidX.RecyclerView.Widget; @@ -28,6 +29,23 @@ protected override AiRecyclerView CreatePlatformView() return new AiRecyclerView(Context, VirtualView); } + protected override void ConnectHandler(AiRecyclerView platformView) + { + base.ConnectHandler(platformView); + + if (SettingsViewConfiguration.ShouldAutoDisconnect) + { + VirtualView.AddCleanUpEvent(); + } + } + + protected override void DisconnectHandler(AiRecyclerView platformView) + { + base.DisconnectHandler(platformView); + + platformView.Dispose(); + } + private static void MapSeparatorColor(SettingsViewHandler handler, SettingsView sv) { handler.PlatformView.UpdateSeparatorColor(); diff --git a/SettingsView/Handlers/SettingsViewHandler.iOS.cs b/SettingsView/Handlers/SettingsViewHandler.iOS.cs index 998c7ab..20f5952 100644 --- a/SettingsView/Handlers/SettingsViewHandler.iOS.cs +++ b/SettingsView/Handlers/SettingsViewHandler.iOS.cs @@ -9,6 +9,7 @@ using Microsoft.Maui.Controls.Compatibility.Platform.iOS; using Microsoft.Maui.Platform; using MobileCoreServices; +using AiForms.Settings.Extensions; namespace AiForms.Settings.Handlers; @@ -42,8 +43,6 @@ protected override AiTableView CreatePlatformView() VirtualView.SectionCollectionChanged += OnSectionCollectionChanged; VirtualView.SectionPropertyChanged += OnSectionPropertyChanged; VirtualView.CellPropertyChanged += OnCellPropertyChanged; - - VirtualView.ParentChanged += ParentChanged; _insetTracker = new KeyboardInsetTracker(_tableview, () => PlatformView.Window, insets => PlatformView.ContentInset = PlatformView.ScrollIndicatorInsets = insets, point => { @@ -55,31 +54,36 @@ protected override AiTableView CreatePlatformView() _contentSizeObserver = _tableview.AddObserver("contentSize", NSKeyValueObservingOptions.New, OnContentSizeChanged); return _tableview; - } - - void ParentChanged(object sender, EventArgs e) + } + + protected override void ConnectHandler(AiTableView platformView) { - Element elm = VirtualView; - - while (elm != null) - { - elm = elm.Parent; - if (elm is Page) - { - break; - } - } - _parentPage = elm as Page; - _parentPage.Appearing += ParentPageAppearing; - VirtualView.ParentChanged -= ParentChanged; + base.ConnectHandler(platformView); + + foreach (var el in VirtualView.GetParentsPath()) + { + if (el is Page page) + { + _parentPage = page; + _parentPage.Appearing += ParentPageAppearing; + } + } + + if (SettingsViewConfiguration.ShouldAutoDisconnect) + { + VirtualView.AddCleanUpEvent(); + } } protected override void DisconnectHandler(AiTableView platformView) { - _parentPage.Appearing -= ParentPageAppearing; - _parentPage = null; + if (_parentPage is not null) + { + _parentPage.Appearing -= ParentPageAppearing; + _parentPage = null; + } - _contentSizeObserver.Dispose(); + _contentSizeObserver?.Dispose(); _contentSizeObserver = null; VirtualView.CollectionChanged -= OnCollectionChanged; diff --git a/SettingsView/MauiAppBuilderExtension.cs b/SettingsView/MauiAppBuilderExtension.cs new file mode 100644 index 0000000..cbf44d3 --- /dev/null +++ b/SettingsView/MauiAppBuilderExtension.cs @@ -0,0 +1,18 @@ +using System; +namespace AiForms.Settings; + +public static class MauiAppBuilderExtension +{ + public static MauiAppBuilder UseSettingsView(this MauiAppBuilder builder, bool shouldCallDisconnectHandlerWhenPageUnloaded = false) + { + builder.ConfigureMauiHandlers(handler => + { + handler.AddSettingsViewHandler(); + }); + + SettingsViewConfiguration.ShouldAutoDisconnect = shouldCallDisconnectHandlerWhenPageUnloaded; + + return builder; + } +} + diff --git a/SettingsView/Platforms/Android/Cells/CellBaseView.cs b/SettingsView/Platforms/Android/Cells/CellBaseView.cs index 91dcd47..99ef679 100644 --- a/SettingsView/Platforms/Android/Cells/CellBaseView.cs +++ b/SettingsView/Platforms/Android/Cells/CellBaseView.cs @@ -611,7 +611,12 @@ protected override void Dispose(bool disposing) _imageLoader?.Reset(); _imageLoader = null; - if(_cell != null) + if (CellParent != null) + { + CellParent.PropertyChanged -= ParentPropertyChanged; + } + + if (_cell != null) { _cell.PropertyChanged -= CellPropertyChanged; if (_cell.Section != null) @@ -622,11 +627,8 @@ protected override void Dispose(bool disposing) //CellRenderer.SetRealCell(_cell, null); _cell = null; - } - - CellParent.PropertyChanged -= ParentPropertyChanged; + } - HintLabel?.Dispose(); HintLabel = null; TitleLabel?.Dispose(); diff --git a/SettingsView/SettingsView.csproj b/SettingsView/SettingsView.csproj index 92f621a..4da0de1 100644 --- a/SettingsView/SettingsView.csproj +++ b/SettingsView/SettingsView.csproj @@ -21,7 +21,7 @@ This is a flexible TableView specialized in settings for Android / iOS. There are various cells such as (LabelCell,ButtonCell,CommandCell,SwitchCell,CheckboxCell,RadioCell,PickerCell,EntryCell,NumberPickerCell,TimePickerCell,DatePickerCell,CustomCell) - Fix iOS Header/FooterView issue + Fix DisconnectHandler MAUI TableView Cell Setting Configuration Option ListView UITableView RecyclerView ReOrder DragDrop diff --git a/SettingsView/SettingsViewConfiguration.cs b/SettingsView/SettingsViewConfiguration.cs new file mode 100644 index 0000000..029f294 --- /dev/null +++ b/SettingsView/SettingsViewConfiguration.cs @@ -0,0 +1,8 @@ +using System; +namespace AiForms.Settings; + +internal static class SettingsViewConfiguration +{ + internal static bool ShouldAutoDisconnect { get; set; } +} +