Mari Barbu
Mari Barbu

Reputation: 93

How to fix "Only the original thread that created a view hierarchy can touch its views" Xamarin Forms on Android

I'm building an app with Xamarin Forms, but only on android. When I run the app I get this error "Only the original thread that created a view hierarchy can touch its views". I have similar pages in my app, but this is the first time I've received this error. I know that is something about the UI thread but I can't figure out where exacly I'm using the wrong thread.

This is the code where the error comes from:

--ViewModel--

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using Xamarin.Forms;
using XamarinApp.Services;
using XamarinApp.Views.Month;

namespace XamarinApp.ViewModels.Month
{
    public class HistoryViewModel : BaseViewModel
    {
        private readonly IMonthService _monthService;
        private ObservableCollection<int> years;
        private ObservableCollection<int> months;
        public int year;
        public int month;
        public HistoryViewModel(IMonthService monthService)
        {
            _monthService = monthService;
            Years = new ObservableCollection<int>();
            Months = new ObservableCollection<int>();
            Title= "History";
            FindCommand = new Command(async () => await GoToYearHistory());
        }
        private async Task GoToYearHistory()
        {
            if (year == 0)
                return;
            await Shell.Current.GoToAsync($"{nameof(YearHistoryPage)}?{nameof(YearHistoryViewModel.Year)}={year}");
        }
            
        public async void GetYearsAndMonths()
        {

            Years.Clear();
            Months.Clear();

            var years = await _monthService.GetYears().ConfigureAwait(false);
            foreach (var year in years)
            {
                Years.Add(year);
            }

            for (int i = 0; i < 12; i++)
            {
                Months.Add(i+1);
            }
           

        }
        
        public ObservableCollection<int> Years
        {
            get => years;
            set
            {
                years = value;
                OnPropertyChanged(nameof(Years));
            }
        }

        public ObservableCollection<int> Months
        {
            get => months;
            set
            {
                months = value;
                OnPropertyChanged(nameof(Months));
            }
        }


        public int Year
        {
            get => year;
            set
            {
                year = value;
                OnPropertyChanged(nameof(Year));
            }
        }
        public int Month
        {
            get => month;
            set
            {
                month = value;
                OnPropertyChanged(nameof(Month));
            }
        }

        public ICommand FindCommand { get; }
    }
}

---Xaml file---

<?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:month="clr-namespace:XamarinApp.ViewModels.Month" x:DataType="month:HistoryViewModel"
             x:Class="XamarinApp.Views.Month.HistoryPage"
             BackgroundColor="{StaticResource BackgroundColor}">
    <ContentPage.Content>
        <StackLayout Orientation="Vertical" Padding="30,24,30,24" Spacing="10">
            <Label Text="History" 
               FontSize="Title" 
               TextColor="{StaticResource Primary}" 
               FontAttributes="Bold"
                HorizontalTextAlignment="Center"
            VerticalTextAlignment="Center" />
            <StackLayout Orientation="Horizontal">
                <Picker Title="Select Year" ItemsSource="{Binding Years}"
                                SelectedItem="{Binding Year}"  HorizontalOptions="FillAndExpand"/>
                <Picker Title="Select Month" ItemsSource="{Binding Months}"
                                SelectedItem="{Binding Month}"  HorizontalOptions="FillAndExpand"/>
            </StackLayout>
            <Button Text="Find" Command="{Binding FindCommand}" Margin="20,40,20,0" CornerRadius="10" HorizontalOptions="FillAndExpand"/>
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

---Xaml.cs file---


using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using XamarinApp.ViewModels.Month;

namespace XamarinApp.Views.Month
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class HistoryPage : ContentPage
    {
        private readonly HistoryViewModel _historyViewModel;
        public HistoryPage()
        {
            InitializeComponent();
            _historyViewModel = Startup.Resolve<HistoryViewModel>();
            BindingContext = _historyViewModel;
        }

        protected override void OnAppearing()
        {
            Device.BeginInvokeOnMainThread(() =>
            {
                _historyViewModel?.GetYearsAndMonths();
            });
           

        }
    }
}

Upvotes: 3

Views: 2124

Answers (1)

Mari Barbu
Mari Barbu

Reputation: 93

So I fixed the problem by removing ConfigureAwait(false) from this line "var years = await _monthService.GetYears().ConfigureAwait(false)" because ConfigureAwait(false) kept me from staying on the UI thread.

Upvotes: 6

Related Questions