Only the original thread that created a view hierarchy can touch its views.

Hi there! First of all, my english is not very well, so please be patient to read my question slowly.

Well, as you can see on the tittle, I got a problem about threads. I'm using a Listview and trying to binding the ItemSource from a viewmodel loaded with data (I'm trying to do something like a timeline using facebook or instagram as example). The case is... when I try to use "Binding" I got this Error Message:

"Unhandled Exception:
Android.Util.AndroidRuntimeException: Only the original thread that created a view hierarchy can touch its views."

Yeah, I know this question has been answered in another threads in the forum with the following code:
"Device.BeginInvokeOnMainThread(() => { NotifyPropertyChanged( nameof(PropertyName) ); });"

But that line is the one that makes de app get into a Break Mode. So... any idea?

Thanks for read.

Answers

  • JohnHardmanJohnHardman GBUniversity mod

    @SourceCodeError

    Can you post the code from the point where the ViewModel is updated with data, to the point where the PropertyChanged event is raised?

    @SourceCodeError said:
    Hi there! First of all, my english is not very well, so please be patient to read my question slowly.

    Although the forum rules say this is an English language forum, my suggestion if you are not confident with English is to ask your question in English as best you can, but then underneath repeat the question in your own language. That way, if your English contains errors, we can always read your native language or pass your native language through a translator.

  • SourceCodeErrorSourceCodeError Member ✭✭
    edited February 21

    @JohnHardman said:
    Although the forum rules say this is an English language forum, my suggestion if you are not confident with English is to >ask your question in English as best you can, but then underneath repeat the question in your own language. That way, >if your English contains errors, we can always read your native language or pass your native language through a >translator.

    Well, you have a good point, i'll do it since now for my future questions :D

    @JohnHardman said:
    @SourceCodeError

    Can you post the code from the point where the ViewModel is updated with data, to the point where the PropertyChanged event is raised?

    This is the xaml code for the listview:

        <ListView x:Name="TimeLineListView"
                     HorizontalOptions="Center"
                     VerticalOptions="CenterAndExpand"
                     Grid.Row="0"
                     ItemsSource="{Binding TimeLineItems, Mode=TwoWay}"
                     RowHeight="665"
                     ItemTapped="PubTapped">
    
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            <local:PublicationCell/>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>
    

    This is the C# code for the NotifyPropertyChanged Method:

        public ObservableCollection<PublicationCell_M> TimeLineItems
                {
                    get { return timeLineItems; }
                    set
                    {
                        timeLineItems = value;
                        Device.BeginInvokeOnMainThread(() =>
                        {
                            NotifyPropertyChanged(nameof(TimeLineItems));
                        });
                    }
           }
    

    Finally, the way I update the bindingcontext value:

    private async void GetTimeLineItems()
        {
    
            await Task.Run(async () =>
            {
    
                var TimeLineValues = new ObservableCollection<PublicationCell_M>();
                Console.WriteLine("start task");
                IsBusy = true;
    
                //Get Publication List
                try
                {
                    UserLocation = await GetLocation();
                    PublicationList = await new PublicationCRUD().GetPublications(UserLocation);
                }
                catch (Exception e)
                {
                    Console.WriteLine($"Exception in {GetType().Name} {e.GetType().Name}:{e.Message} - TimeLine");
                }
    
                //Get First 3 Publications
                for (int Index = 0; Index < 3 & Index < PublicationList.Count; Index++)
                {
                    if (PublicationList[Index] != null)
                    {
                        var PubCell = new PublicationCell_M(PublicationList[Index]);
                        TimeLineValues.Add(PubCell);
                    }
                }
    
                //Set TimeLineItems
                TimeLineListView.ItemsSource = TimeLineValues;
    
                IsBusy = false;
            });
    }
    
  • JoeMankeJoeManke USMember ✭✭✭✭✭

    Why is GetTimeLineItems() an async void method? You should be able to make that an async Task and remove the Task.Run() wrapping the whole method.

  • JohnHardmanJohnHardman GBUniversity mod
    edited February 21

    @SourceCodeError

    There's not enough code shown to be confident of picking up 100% of the problems. However, the first issue will probably be:

    TimeLineListView.ItemsSource = TimeLineValues;
    

    as that affects a UI element, but is being called from a thread other than the UI thread. It's inside the Task.Run block, but not enclosed in Device.BeginInvokeOnMainThread

  • Shiva799Shiva799 Member ✭✭

    I'm getting error in the insertpagebefore
    var root = MasterDetail.Detail.Navigation.NavigationStack[0];
    MasterDetail.Detail.Navigation.InsertPageBefore(page, root);
    Device.BeginInvokeOnMainThread(async () =>
    {
    await MasterDetail.Detail.Navigation.PopToRootAsync(false);
    });

    I'm not sure what is going wrong now?
    It worked fine previously

  • wend0rlinwend0rlin DEMember ✭✭

    same here, did you find any solutions @Shiva799 ?

  • JohnHardmanJohnHardman GBUniversity mod

    @wend0rlin said:
    same here, did you find any solutions @Shiva799 ?

    I suggest starting a new question and posting your code.

    @Shiva799 didn't provide enough information for anybody to answer definitely. However, my guess would be that @Shiva799 was calling Device.BeginInvokeOnMainThread because the code posted just above was in a method returning something other than Task or Task<T>. If that were the case, then there were probably race conditions or other issues in code that was not included in the post above.

Sign In or Register to comment.