xamarin / Xamarin.Forms

Xamarin.Forms is no longer supported. Migrate your apps to .NET MAUI.
https://aka.ms/xamarin-upgrade
Other
5.62k stars 1.87k forks source link

In Xamarin.Forms.UWP, Unable to set Automation ID to custom control, if not used SetNativeControl() method #14226

Open Eswaran17392 opened 3 years ago

Eswaran17392 commented 3 years ago

Description

I am creating a custom control in Xamarin.Forms which is inherited from TemplatedView and using the application in all three platforms. For testing purposes, I need to set Automation ID for all native controls.

Usually, by using AutomationPeer we can set Automation ID to native UWP control from the UWP renderer project. But, in my custom control, I get this. Control is null always.

So, I can’t set Automation ID in UWP renderer class as Forms TemplatedView is a FrameworkElement in UWP.

My query is,

How to get a native element (this.Control) in the UWP renderer project for Xamarin.Forms TemplatedView.

How to set Automation Id to native UWP control if this.Control is null.

Expected Behavior

Set Automation ID to custom control

Actual Behavior

Since this.Control is null, Unable to set Automation ID to custom control

The code snippet is provided below:

` class FormsCustomLayout : TemplatedView

 {
     public static readonly BindableProperty InputViewProperty =
         BindableProperty.Create(nameof(InputView), typeof(View), typeof(FormsCustomLayout), null, BindingMode.Default, null, OnInputViewChanged);

     private static void OnInputViewChanged(BindableObject bindable, object oldValue, object newValue)
     {
         (bindable as FormsCustomLayout).OnInputViewChanged(oldValue, newValue);
     }

     private void OnInputViewChanged(object oldValue, object newValue)
     {
         var oldView = (View)oldValue;
         if (oldView != null)
         {
             if (this.contentGrid.Children.Contains(oldView))
             {
                 oldView.SizeChanged -= OnInputViewSizeChanged;
                 oldView.BindingContext = null;
                 this.contentGrid.Children.Remove(oldView);
             }
         }

         var newView = (View)newValue;
         if (newView != null)
         {
             newView.SizeChanged += OnInputViewSizeChanged;
             newView.VerticalOptions = LayoutOptions.CenterAndExpand;
             newView.HeightRequest = 60;
              this.contentGrid.Children.Add(newView);
         }
     }

     private void OnInputViewSizeChanged(object sender, EventArgs e)
     {

     }

     public  View InputView
     {
         get { return (View)GetValue(InputViewProperty); }
         set { SetValue(InputViewProperty, value); }
     }

     internal void UpdateText(object text)
     {
         this.Text = (string)text;
     }

     private readonly Grid contentGrid = new Grid();

     public FormsCustomLayout()
     {
         this.ControlTemplate = new ControlTemplate(typeof(StackLayout));
         ((StackLayout)Children[0]).Children.Add(this.contentGrid);
         if (InputView != null)
         {
             this.contentGrid.Children.Add(InputView);
         }
     }

     internal string Text { get; private set; }
 }

`

The custom renderer code snippet is provided below:

` class FormsCustomLayoutRenderer : ViewRenderer<FormsCustomLayout, FrameworkElement>

 {
     /// <summary>
     /// Method that is called when the automation id is set.
     /// </summary>
     /// <param name="id">The automation id.</param>
     protected override void SetAutomationId(string id)
     {
         if (this.Control == null)
         {
             base.SetAutomationId(id);
         }
         else
         {
             this.SetAutomationPropertiesAutomationId(id);
             this.Control.SetAutomationPropertiesAutomationId(id);
         }
     }

     /// <summary>
     /// Provide automation peer for the control
     /// </summary>
     /// <returns>The TextInputLayout view automation peer.</returns>
     protected override AutomationPeer OnCreateAutomationPeer()
     {
         if (this.Control == null)
         {
             return new FormsCustomLayoutAutomationPeer(this);
         }

         return new FormsCustomLayoutAutomationPeer(this.Control);
     }

     protected override void OnElementChanged(ElementChangedEventArgs<FormsCustomLayout> e)
     {
         base.OnElementChanged(e);
         var element = e.NewElement;           
     }           
 }
 internal class FormsCustomLayoutAutomationPeer : FrameworkElementAutomationPeer
 {
     /// <summary>
     /// Initializes a new instance of the <see cref="FormsCustomLayoutRenderer"/> class.
     /// </summary>
     /// <param name="owner">FormsCustomLayout View control</param>
     public FormsCustomLayoutAutomationPeer(FrameworkElement owner) : base(owner)
     {
     }

     /// <summary>
     /// Describe the control type
     /// </summary>
     /// <returns>The control type.</returns>
     protected override AutomationControlType GetAutomationControlTypeCore()
     {
         return AutomationControlType.Custom;
     }

     /// <summary>
     /// Describe the class name.
     /// </summary>
     /// <returns>The Class Name.</returns>
     protected override string GetClassNameCore()
     {
         return "FormsCustomLayout";
     }
 }

`

Please get the sample from the below link: Custom Sample

Yuvasrisivakumar commented 3 years ago

Any update on this?