question

JassimAlRahma-9056 avatar image
0 Votes"
JassimAlRahma-9056 asked LeonLu-MSFT edited

NULL error with FindByName

Hi,

I am getting:

Object reference not set to an instance of an object

when trying FindByName this way:

StackLayoutPostDetails.FindByName<Label>("LabelPostGender").Text = "OK";

Here is my XAML:

 <StackLayout x:Name="StackLayoutPostDetails" HorizontalOptions="FillAndExpand"  VerticalOptions="FillAndExpand">
     <BindableLayout.ItemTemplate>
         <DataTemplate>
             <Grid>
             <Grid.RowDefinitions>
                 <RowDefinition Height="Auto" />
                 <RowDefinition Height="Auto" />
             </Grid.RowDefinitions>
    
             <Grid Grid.Row="1" Margin="0,10,5,5">
                 <Grid.ColumnDefinitions>
                     <ColumnDefinition Width="Auto" />
                     <ColumnDefinition Width="*" />
                 </Grid.ColumnDefinitions>
    
                 <Image Grid.Column="0" WidthRequest="30" HeightRequest="30" Margin="5" HorizontalOptions="Center" VerticalOptions="End">
                 <Image.Source>
                     <FontImageSource FontFamily="FontRegular" Glyph="&#xf044;" Color="Red" />
                 </Image.Source>
                 <Image.GestureRecognizers>
                     <TapGestureRecognizer Tapped="TapGestureRecognizerShowGender_Tapped" NumberOfTapsRequired="1" />
                 </Image.GestureRecognizers>
                 </Image>
    
                 <StackLayout Grid.Column="1" Orientation="Horizontal" Margin="5" >
                     <Label Text="Gender : " VerticalOptions="Center" />
                     <Label x:Name="LabelPostGender" Text="{Binding gender_name}" VerticalOptions="Center" />
                 </StackLayout>
             </Grid>
             </Grid>
             </DataTemplate>
     </BindableLayout.ItemTemplate>
 </StackLayout>

Thanks,
Jassim



dotnet-csharpdotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

LeonLu-MSFT avatar image
0 Votes"
LeonLu-MSFT answered LeonLu-MSFT edited

Hello,​

Welcome to our Microsoft Q&A platform!

Get your control by FindByName<> in your DataTemplate code. It is not recommand way. You could get the control and set the value by Data Binding.

https://docs.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/data-binding/

Because they are in different NameScopes if you use this datatemplate in the listview or collectionview. The Xaml parser creates one NameScope per Xaml root object in your file, and then different NameScopes for DataTemplates. Here is a similar thread:https://stackoverflow.com/a/42854892

Do you want to achieve the function that click the Image, then text of LabelPostGender will be changed?

If so, I achieve simple code with data-binding.

First of all, I create a model called PlatformInfo.cs, it achieve the INotifyPropertyChanged for update at the runtime.

public class PlatformInfo : INotifyPropertyChanged
    {
        private bool _isChecked;
        private string _platformName;

        public bool IsChecked
        {
            get { return _isChecked; }
            set { _isChecked = value; NotifyPropertyChanged(); }
        }

        public string PlatformName
        {
            get { return _platformName; }
            set { _platformName = value; NotifyPropertyChanged(); }
        }

        public event PropertyChangedEventHandler PropertyChanged;
        public void NotifyPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = "")
        {
            if (this.PropertyChanged != null)
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }
    }


Then I achieve a viewModel, that I add binding data and command. ChangeTextCommmand will binding to the Image's TapGestureRecognizer command. If this command is invoked, PlatformName's text will be changed.

public class ViewModel
    {
        public ViewModel()
        {
            this.GetContactsList();
        }

        public List<PlatformInfo> PlatformsList { get; set; }
        public ICommand ChangeTextCommmand { get; set; }

        private void GetContactsList()
        {
            if (this.PlatformsList == null)
                this.PlatformsList = new List<PlatformInfo>();

            this.PlatformsList.Add(new PlatformInfo() { IsChecked = true, PlatformName = "Android" });
            this.PlatformsList.Add(new PlatformInfo() { IsChecked = true, PlatformName = "iOS" });
            this.PlatformsList.Add(new PlatformInfo() { IsChecked = false, PlatformName = "UWP" });

            ChangeTextCommmand=new Command((Myobject) =>
            {
                PlatformInfo  platformInfo= Myobject as PlatformInfo;

                platformInfo.PlatformName = "tes";
            });
        }
    }


Here is test xaml layout.

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:imagelongclickdemo="clr-namespace:ImageLongClickDemo"
             x:Class="ImageLongClickDemo.MainPage">

    <ContentPage.BindingContext>
        <imagelongclickdemo:ViewModel />
    </ContentPage.BindingContext>
    <StackLayout x:Name="StackLayoutPostDetails" HorizontalOptions="FillAndExpand"  VerticalOptions="FillAndExpand" BindableLayout.ItemsSource="{Binding PlatformsList}"     >

      
        <BindableLayout.ItemTemplate>
                <DataTemplate>
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="Auto" />
                            <RowDefinition Height="Auto" />
                        </Grid.RowDefinitions>

                        <Grid Grid.Row="1" Margin="0,10,5,5">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="Auto" />
                                <ColumnDefinition Width="*" />
                            </Grid.ColumnDefinitions>
                        
                        <Image x:Name="myImage" Grid.Column="0" WidthRequest="30" Source="icon1.png" HeightRequest="30" Margin="5" HorizontalOptions="Center" VerticalOptions="End">
                               
                                <Image.GestureRecognizers>
                                <TapGestureRecognizer Command="{Binding BindingContext.ChangeTextCommmand , Source={x:Reference Name=StackLayoutPostDetails}}" CommandParameter="{Binding .}" NumberOfTapsRequired="1" />
                                </Image.GestureRecognizers>
                        </Image>

                            <StackLayout x:Name="Mysl" Grid.Column="1" Orientation="Horizontal" Margin="5" >
                                <Label Text="Gender : " VerticalOptions="Center" />
                                <Label x:Name="LabelPostGender" Text="{Binding PlatformName}" VerticalOptions="Center" />
                            </StackLayout>
                        </Grid>
                    </Grid>
                </DataTemplate>
            </BindableLayout.ItemTemplate>
        </StackLayout>
   
   

</ContentPage>


Best Regards,

Leon Lu



If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.


· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Thanks @LeonLu-MSFT

But What if I still want to use the FindByName? How to get that?

0 Votes 0 ·

@JassimAlRahma-9056 If you want to use FindByName, we have to get the control step by step. Firstly, we can use FindByName to get the root StackLayout, then If we DataTemplate have serveral Girds, we use stackLayoutPostDetails.Children[0] to get the first Grid(If you want to get the second gird, you can use stackLayoutPostDetails.Children[1] to get it). Then we get the Gird layer, we can use grid.FindByName<StackLayout>("Mysl") to get the Label's outside layout(Please notice I add the x:Name="Mysl" for StackLayout), If we get the nested StackLayout called gridChild, we can use gridChild.FindByName<Label>("LabelPostGender"); to get the Label that we want to change text. It is complicated. So I recommand you to use data-binding.

StackLayout stackLayoutPostDetails =  this.FindByName<StackLayout>("StackLayoutPostDetails");
            Grid grid= stackLayoutPostDetails.Children[0] as Grid;
            Image image= grid.FindByName<Image>("myImage");
            StackLayout gridChild= grid.FindByName<StackLayout>("Mysl");
            Label label= gridChild.FindByName<Label>("LabelPostGender");
            label.Text = "this is test text";
0 Votes 0 ·

@JassimAlRahma-9056 May I know if you have got any chance to check my answer? I am glad to help if you have any other questions

0 Votes 0 ·