How to resolve cannot convert from 'Foundation.NSObject[]' to 'Foundation.NSObject?' in iOS dependency service?

John Hardman 261 Reputation points
2020-11-30T13:07:34.647+00:00

The following code is work-in-progress. Once working, the intention is that it can be used on iOS to set the accessibility order of controls on a Xamarin.Forms ContentPage using a dependency service.

I am currently hitting two problems with this. The first is a compile-time error:
CS1503: Argument 2: cannot convert from 'Foundation.NSObject[]' to 'Foundation.NSObject?'
I have commented in the code where that is reported.

The second (if I comment out the code that doesn't compile) is that when debugging in Visual Studio, VS shows the nativeViews array as containing XF renderers, not UIViews. I assume that this is some VS weirdness, but could be wrong.

Can anybody assist with either of these, particularly the compile-time error?

    private IVisualElementRenderer GetRenderer(VisualElement xfVisualElement)
    {
        IVisualElementRenderer renderer = Platform.GetRenderer(xfVisualElement);
        if (renderer == null)
        {
            renderer = Platform.CreateRenderer(xfVisualElement);
            Platform.SetRenderer(xfVisualElement, renderer);
        }

        return renderer;
    }

    private UIView GetNativeView(VisualElement xfVisualElement) 
        => GetRenderer(xfVisualElement).NativeView;

    public void SetReadingOrder(VisualElement xfContainingElement, VisualElement[] xfVisualElements)
    {
        if (GetNativeView(xfContainingElement) is IUIAccessibilityContainer accessibilityContainer)
        {
            if (xfVisualElements.Length > 0)
            {
                NSObject[] nativeViews = new UIView[xfVisualElements.Length];

                int index = 0;
                foreach (VisualElement xfVisualElement in xfVisualElements)
                    nativeViews[index++] = GetNativeView(xfVisualElement).Self;

                // The following line results in the compile-time error
                // CS1503: Argument 2: cannot convert from 'Foundation.NSObject[]' to 'Foundation.NSObject?'
                accessibilityContainer.SetAccessibilityElements(nativeViews);
            }
            else
            {
                accessibilityContainer.SetAccessibilityElements(null);
            }
        }
    }

Note that if I look at the definition of UIAccessibilityContainer, it appears as follows:

namespace UIKit
{
    [Protocol(Name = "UIAccessibilityContainer", WrapperType = typeof(UIAccessibilityContainerWrapper), IsInformal = true)]
    [ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "AccessibilityElementCount", Selector = "accessibilityElementCount", ReturnType = typeof(nint))]
    [ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "GetAccessibilityElementAt", Selector = "accessibilityElementAtIndex:", ReturnType = typeof(NSObject), ParameterType = new[] { typeof(nint) }, ParameterByRef = new[] { false })]
    [ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "GetIndexOfAccessibilityElement", Selector = "indexOfAccessibilityElement:", ReturnType = typeof(nint), ParameterType = new[] { typeof(NSObject) }, ParameterByRef = new[] { false })]
    [ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "GetAccessibilityElements", Selector = "accessibilityElements", ReturnType = typeof(NSObject))]
    [ProtocolMember(IsRequired = false, IsProperty = false, IsStatic = false, Name = "SetAccessibilityElements", Selector = "setAccessibilityElements:", ParameterType = new[] { typeof(NSObject) }, ParameterByRef = new[] { false })]
    [ProtocolMember(IsRequired = false, IsProperty = true, IsStatic = false, Name = "AccessibilityContainerType", Selector = "accessibilityContainerType", PropertyType = typeof(UIAccessibilityContainerType), GetterSelector = "accessibilityContainerType", SetterSelector = "setAccessibilityContainerType:", ArgumentSemantic = ArgumentSemantic.Assign)]
    public interface IUIAccessibilityContainer : INativeObject, IDisposable
    {
    }
}
Xamarin
Xamarin
A Microsoft open-source app platform for building Android and iOS apps with .NET and C#.
5,292 questions
0 comments No comments
{count} votes

Accepted answer
  1. John Hardman 261 Reputation points
    2020-11-30T15:55:59.36+00:00

    The line with the compile-time error, needed replacing with:

    accessibilityContainer.SetAccessibilityElements(NSArray.FromNSObjects(nativeViews));
    

    Having done that, the accessibility order seems to be set as expected.
    (Note that I haven't checked for resource leaks yet, so the code shown might not be 100% yet).

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. acmeaney 76 Reputation points
    2020-11-30T15:01:45.09+00:00

    SetAccessibilityElements takes an NSObject, which an array of NSObjects is not.

    You have to pass the method the type it expects for the code to work.

    I assume that the object nativeViews is supposed to be wrapped in something, but I am unfamiliar with accessibility so you will have to do some more research.