Xamarin.iOS AddObserver未触发更改事件以更新到UIView.Window

r1zk6ea1  于 2022-12-07  发布在  iOS
关注(0)|答案(1)|浏览(131)

我尝试在Xamarin.Forms中实现生命周期效果,但在iOS版本中遇到了问题。由于某种原因,我似乎无法观察到窗口更改通知事件。下面是我的代码:

public class CustomLifeCycleEffectRouter : PlatformEffect
{
    private const NSKeyValueObservingOptions ObservingOptions = NSKeyValueObservingOptions.Initial | NSKeyValueObservingOptions.New;

    UIView? _nativeView;
    CustomLifeCycleEffect? _lifeCycleEffect;
    IDisposable _isLoadedObserverDisposable;

    protected override void OnAttached()
    {
        _lifeCycleEffect = Element.Effects.OfType<CustomLifeCycleEffect>().FirstOrDefault() ?? throw new ArgumentNullException($"The effect {nameof(CustomLifeCycleEffect)} can't be null.");

        _nativeView = Control ?? Container;

        _isLoadedObserverDisposable = _nativeView?.AddObserver("window", ObservingOptions, isWindowAttachedObserver);
    }

    protected override void OnDetached()
    {
        _lifeCycleEffect?.RaiseUnloadedEvent(Element);
        _isLoadedObserverDisposable.Dispose();
    }
    
    private void isWindowAttachedObserver(NSObservedChange nsObservedChange)
    {
        if (_nativeView.Window != null)
            _lifeCycleEffect?.RaiseLoadedEvent(Element);
        else
            _lifeCycleEffect?.RaiseUnloadedEvent(Element);
    }
}

我很清楚Xamarin.CommunityToolkit也有类似的效果,但是它提前触发了事件;我需要它在我可以导航到根父节点的层次结构时启动。有人能看出问题吗?

编辑

我创建了一个小样本来复制我的行为和问题。可以在这里查看:
https://github.com/sonic1015/LifeCycleEffectTesting
目标是在调试输出中只显示以下消息:
$" {elementName}已经是一个页面。"
$" {元素名称}是{页面名称}的子项。"
而不是这些:
$" {elementName}没有父项???"。
$"如何加载{elementName}且在层次结构中没有父级???"
$" WTF???我们从未加载{elementName}。"
这些消息可以在"ViewExtensions"类中找到,我的目标是让每个用户创建的视图都发出好的消息。

我注意到一件事:

我还在平台项目中包含了一个Xamarin Community Toolkit版本的router效果的变体,它实际上是有效的,除了看起来如果任何视图被模板化,当它还没有父视图时,它会"加载"。我想这就是为什么它最初对我不起作用的原因,所以如果我能找到一种方法来解决这个小问题,我可以用那个版本的路由效应。

vql8enpb

vql8enpb1#

1.Create a ViewLifecycleEffect class that implements RoutingEffect in the shared project like below:

public class ViewLifecycleEffect : RoutingEffect
{
    public const string EffectGroupName = "XFLifecycle";
    public const string EffectName = "LifecycleEffect";
 
    public event EventHandler<EventArgs> Loaded;
    public event EventHandler<EventArgs> Unloaded;
 
    public ViewLifecycleEffect() : base($"{EffectGroupName}.{EffectName}") { }
 
    public void RaiseLoaded(Element element) => Loaded?.Invoke(element, EventArgs.Empty);
    public void RaiseUnloaded(Element element) => Unloaded?.Invoke(element, EventArgs.Empty);
}

2.In Mainpage.xmal:

<StackLayout x:Name="MainContainer" Margin="20" VerticalOptions="Center" HorizontalOptions="Center">
    <Button Text="CLICK TO REMOVE" Clicked="Button_OnClicked" HorizontalOptions="Center" VerticalOptions="Center">
        <Button.Effects>
            <effects:ViewLifecycleEffect Loaded="ViewLifecycleEffect_OnLoaded" Unloaded="ViewLifecycleEffect_OnUnloaded"/>
        </Button.Effects>
    </Button>
</StackLayout>

Code-behind:

public partial class MainPage : ContentPage
{
    public MainPage()
    {
        InitializeComponent();
    }
 
    private void Button_OnClicked(object sender, EventArgs e)
    {
        MainContainer.Children.Clear();
    }
 
    private void ViewLifecycleEffect_OnLoaded(object sender, EventArgs e)
    {
        DisplayAlert("LOADED", "Button was added", "OK");
    }
 
    private void ViewLifecycleEffect_OnUnloaded(object sender, EventArgs e)
    {
        DisplayAlert("UNLOADED", "Button was removed", "OK");
    }
}

3.Create a IosLifecycleEffect in the iOS project.

[assembly:ResolutionGroupName(ViewLifecycleEffect.EffectGroupName)]
[assembly:ExportEffect(typeof(IosLifecycleEffect), ViewLifecycleEffect.EffectName)]
namespace XFLifecycle.iOS.Effects
{
    public class IosLifecycleEffect : PlatformEffect
    {
        private const NSKeyValueObservingOptions ObservingOptions = NSKeyValueObservingOptions.Initial | NSKeyValueObservingOptions.OldNew | NSKeyValueObservingOptions.Prior;
 
        private ViewLifecycleEffect _viewLifecycleEffect;
        private IDisposable _isLoadedObserverDisposable;
 
        protected override void OnAttached()
        {
            _viewLifecycleEffect = Element.Effects.OfType<ViewLifecycleEffect>().FirstOrDefault();
             
            UIView nativeView = Control ?? Container;
            _isLoadedObserverDisposable = nativeView?.AddObserver("superview", ObservingOptions, IsViewLoadedObserver);
        }
 
        protected override void OnDetached()
        {
            _viewLifecycleEffect.RaiseUnloaded(Element);
            _isLoadedObserverDisposable.Dispose();
        }
 
        private void IsViewLoadedObserver(NSObservedChange nsObservedChange)
        {
            if (!nsObservedChange.NewValue.Equals(NSNull.Null))
                _viewLifecycleEffect?.RaiseLoaded(Element);
            else if (!nsObservedChange.OldValue.Equals(NSNull.Null))
                _viewLifecycleEffect?.RaiseUnloaded(Element);
        }
    }
}

相关问题