Tijl .Reynhout
Tijl .Reynhout

Reputation: 1063

Exception on Xamarin: System.ObjectDisposedException: Cannot access a disposed object 'Xamarin.Forms.Platform.Android.FastRenderers.LabelRenderer'

I am using Xamarin.Forms to build an app for Android and I'm currently getting the following error: System.ObjectDisposedException: Cannot access a disposed object 'Xamarin.Forms.Platform.Android.FastRenderers.LabelRenderer'. The Xamarin.Forms version I am using is 4.8.0.1364

My code for the XAML is the following:

<?xml version="1.0" encoding="UTF-8"?>
<ContentView
  x:Class="Peripass.YardAssetManagementApp.UI.Views.MainTaskListViewContent"
  xmlns="http://xamarin.com/schemas/2014/forms"
  xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
  xmlns:converters="clr-namespace:Peripass.Mobile.Framework.Converters;assembly=Peripass.Mobile.Framework"
  xmlns:d="http://xamarin.com/schemas/2014/forms/design"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  xmlns:uiControls="clr-namespace:Peripass.Mobile.Framework.UIControls;assembly=Peripass.Mobile.Framework"
  mc:Ignorable="d"
  x:Name="tasksPage">
  <ContentView.Resources>
    <ResourceDictionary>
      <converters:ItemTappedEventArgsToTappedItemConverter x:Key="ItemTappedConverter" />
    </ResourceDictionary>
  </ContentView.Resources>
  <ContentView.Content>
    <!-- All Tasks -->
    <StackLayout
      BackgroundColor="White"
      VerticalOptions="FillAndExpand">
      <!-- ActivityIndicator -->
      <StackLayout
        Padding="0,20,0,0"
        BackgroundColor="White"
        IsVisible="{Binding Model.ShowLoadingIndicator}">
        <ActivityIndicator BackgroundColor="White" 
                               
                           Color="#28aa90" 
                           HeightRequest="40"
                           WidthRequest="40"
                           IsRunning="{Binding Model.ShowLoadingIndicator}"
                           IsVisible="{Binding Model.ShowLoadingIndicator}">

        </ActivityIndicator>
        <Label FontSize="14" Text="fetching tasks" TextColor="DimGray" HorizontalTextAlignment="Center" HorizontalOptions="FillAndExpand"></Label>
      </StackLayout>

      <RefreshView Command="{Binding RefreshCommand}" IsRefreshing="{Binding IsRefreshing, Mode=OneWay}">
        <CollectionView x:Name="tasks" ItemsSource="{Binding Model.AllTasks}" ItemSizingStrategy="MeasureAllItems" VerticalOptions="FillAndExpand">
          <CollectionView.ItemTemplate>
            <DataTemplate>
              <StackLayout BackgroundColor="{Binding RowBackGroundColor}">
                <StackLayout.GestureRecognizers>
                  <TapGestureRecognizer CommandParameter="{Binding TaskId}" Command="{Binding Source={x:Reference tasks}, Path=BindingContext.TappedGotoTaskDetailCommand}"/>
                </StackLayout.GestureRecognizers>
                <Grid>
                  <Grid.RowDefinitions>
                    <RowDefinition Height="73" />
                    <RowDefinition Height="*" />
                  </Grid.RowDefinitions>
                  <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="65" />
                    <ColumnDefinition Width="*" />
                    <ColumnDefinition Width="75" />
                  </Grid.ColumnDefinitions>
                  <uiControls:PpIcon
                            Grid.Row="0"
                            Grid.Column="0"
                            Margin="5"
                            IconChar="{Binding LeftIconChar}"
                            IconColor="{Binding LeftIconColor}"
                            IconSize="42" />

                  <Grid Grid.Row="0" Grid.Column="1">
                    <Grid.RowDefinitions>
                      <RowDefinition Height="50*" />
                      <RowDefinition Height="50*" />
                    </Grid.RowDefinitions>
                    <Grid.ColumnDefinitions>
                      <ColumnDefinition Width="*" />
                      <ColumnDefinition Width="Auto" />
                    </Grid.ColumnDefinitions>

                    <Label
                      FontAttributes="Bold"
                      FontSize="21"
                      HorizontalTextAlignment="Start"
                      LineBreakMode="TailTruncation"
                      Text="{Binding TaskLine1}"
                      TextColor="{StaticResource PeripassBlack}"
                      TranslationY="7"
                      VerticalTextAlignment="Center" />
                    

                    <StackLayout
                              Grid.Row="0"
                              Grid.RowSpan="2"
                              Grid.Column="1"
                              Margin="0"
                              Padding="0"
                              Orientation="Horizontal"
                              Spacing="0"
                              TranslationX="4">
                      <Label
                                FontAttributes="Bold"
                                FontSize="21"
                                HorizontalOptions="End"
                                HorizontalTextAlignment="Start"
                                Text="{Binding StepProgressLineStepsDone}"
                                TextColor="{Binding RightIconColor}"
                                VerticalTextAlignment="Center" />

                      <Label
                                FontSize="21"
                                HorizontalOptions="End"
                                HorizontalTextAlignment="Start"
                                Text="/"
                                TextColor="{Binding RightIconColor}"
                                VerticalTextAlignment="Center" />

                      <Label
                                FontSize="21"
                                HorizontalOptions="End"
                                HorizontalTextAlignment="Start"
                                Text="{Binding StepProgressLineStepsTotal}"
                                TextColor="{Binding RightIconColor}"
                                VerticalTextAlignment="Center" />
                    </StackLayout>

                    <Label
                              Grid.Row="1"
                              Grid.Column="0"
                              FontSize="16"
                              HorizontalTextAlignment="Start"
                              LineBreakMode="TailTruncation"
                              Text="{Binding TaskLine2}"
                              TextColor="{StaticResource PeripassBlack}"
                              VerticalOptions="StartAndExpand"
                              VerticalTextAlignment="Center" />


                  </Grid>

                  <uiControls:PpIcon
                            Grid.Row="0"
                            Grid.Column="2"
                            Margin="15"
                            IconChar="{Binding RightIconChar}"
                            IconColor="{Binding RightIconColor}"
                            IconSize="42" />

                  <Label
                    Grid.Row="1"
                    Grid.Column="1"
                    Grid.ColumnSpan="2"
                    FontSize="16"
                    HorizontalTextAlignment="Start"
                    LineBreakMode="TailTruncation"
                    Text="{Binding DisplayName}"
                    TextColor="{StaticResource PeripassBlack}"
                    VerticalOptions="StartAndExpand"
                    VerticalTextAlignment="Center"
                    IsVisible="{Binding Source={x:Reference tasksPage}, Path=BindingContext.Model.IsSearching}"
                    />
                </Grid>
              </StackLayout>
            </DataTemplate>
          </CollectionView.ItemTemplate>
          <CollectionView.EmptyView>
            <StackLayout>
              <StackLayout HeightRequest="100" BackgroundColor="#D6D6D6" Margin="10,10,10,10">
                <Label HorizontalOptions="Center" VerticalOptions="CenterAndExpand" FontSize="20" Text="No tasks available" TextColor="{StaticResource PeripassBlack}"/>
              </StackLayout>
            </StackLayout>
          </CollectionView.EmptyView>
        </CollectionView>
      </RefreshView>
    </StackLayout>
  </ContentView.Content>
</ContentView>

The code for the ViewModel

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using Peripass.ApiModels;
using Peripass.Mobile.Framework.DependencyInterfaces;
using Peripass.YardAssetManagementApp.Data;
using Peripass.YardAssetManagementApp.Data.LocalDataServices;
using Peripass.YardAssetManagementApp.Data.Syncing.QueueItemSyncActions;
using Peripass.YardAssetManagementApp.DomainModel.V1;
using Peripass.YardAssetManagementApp.DomainModel.V1.Extensions;
using Peripass.YardAssetManagementApp.Events;
using Peripass.YardAssetManagementApp.Icons;
using Peripass.YardAssetManagementApp.Models;
using Peripass.YardAssetManagementApp.MVVM;
using Peripass.YardAssetManagementApp.UI.TopHeaders;
using Xamarin.Forms;

namespace Peripass.YardAssetManagementApp.ViewModels {
  public class MainTaskListViewModel : ViewModelBase<MainTaskListModel> {
    private readonly ILocalTaskDataService _localTaskDataService;
    private readonly ILocalLocationDataService _localLocationDataService;
    private readonly IToMobileTasksSyncer _toMobileTasksSyncer;
    private List<YardOperatorTask> _tasks;
    private readonly ILocalUserDataService _localUserDataService;

    public MainTaskListViewModel(ILocalTaskDataService localTaskDataService, ILocalLocationDataService localLocationDataService, IToMobileTasksSyncer toMobileTasksSyncer, ILocalUserDataService localUserDataService) {
      _localTaskDataService = localTaskDataService;
      _localLocationDataService = localLocationDataService;
      _toMobileTasksSyncer = toMobileTasksSyncer;
      _localUserDataService = localUserDataService;
      MessagingCenter.Unsubscribe<ToMobileTasksSyncer>(this, EventTypes.FetchingTasks.ToString());
      MessagingCenter.Unsubscribe<ToMobileTasksSyncer>(this, EventTypes.LocalTasksUpdated.ToString());
      MessagingCenter.Unsubscribe<IQueueItemSyncAction>(this, EventTypes.LocalTasksUpdated.ToString());
      MessagingCenter.Unsubscribe<ToMobileTasksSyncer>(this, EventTypes.FetchingTasksFailed.ToString());
      SubscribeToTaskFetches();
      _tasks = new List<YardOperatorTask>();
    }
    public ICommand TappedGotoTaskDetailCommand => new Command<int>(async (taskId) => await ExecuteGotoTaskDetail(taskId));
    public ICommand RefreshCommand => new Command(ExecuteRefreshCommand);

    private void SubscribeToTaskFetches() {
      MessagingCenter.Subscribe<ToMobileTasksSyncer>(this, EventTypes.FetchingTasks.ToString(), sender => {
        Model.ShowLoadingIndicator = true;
      });
      MessagingCenter.Subscribe<ToMobileTasksSyncer>(this, EventTypes.LocalTasksUpdated.ToString(), _ => OnTasksUpdated());
      MessagingCenter.Subscribe<IQueueItemSyncAction>(this, EventTypes.LocalTasksUpdated.ToString(), _ => OnTasksUpdated());
      MessagingCenter.Subscribe<ToMobileTasksSyncer>(this, EventTypes.FetchingTasksFailed.ToString(), sender => {
        Model.ShowLoadingIndicator = false;
      });
    }

    private void OnTasksUpdated() {
      Model.ShowLoadingIndicator = false;
      GetTasks();
      MapToModel();
    }

    public bool IsRefreshing { get; set; }

    private async void ExecuteRefreshCommand() {
      try {
        if (IsRefreshing) {
          return;
        }

        IsRefreshing = true;
        await _toMobileTasksSyncer.SyncAllData();
      }
      catch {
        await NavigationService.NavigateToViewModelAsync<GenericExceptionPageViewModel>();
      }
      finally {
        IsRefreshing = false;
      }
    }

    public override void OnInit(object param) {
      SetTopHeader();
    }

    private void SetTopHeader() {
      var topHeader = new TopHeaderForAllTasksContentView(SearchTextChangedAction, StopSearchAction);
      topHeader.SetLine("Task List");
      NavigationService.SetTopHeader(TopHeaderTappedBackCommand, topHeader);
      NavigationService.SetTopHeaderVisible(true);
    }

    public override void OnAppeared() {
      GetTasks();
      MapToModel();
    }

    private void GetTasks() {
      _tasks = _localTaskDataService
        .GetAllTasks()
        .Where(task => task.Status == TaskStatusEnum.Unassigned || task.Status == TaskStatusEnum.Started && task.AssignedOperatorId == _localUserDataService.GetCurrentUser().UserTechnicalId)
        .ToList();
    }

    private async Task ExecuteGotoTaskDetail(int taskId) {
      await NavigationService.NavigateToViewModelAsync<TaskDetailViewModel>(taskId);
    }

    private void StopSearchAction() {
      DependencyService.Get<IDeviceKeyboardHelper>().HideKeyboard();
      MapToModel();
    }

    private void SearchTextChangedAction(string searchText) {
      MapToModel(searchText);
    }

    private void TopHeaderTappedBackCommand() {
      NavigationService.ShowMenu();
    }

    private void MapToModel(string searchOn = "") {
      Model.IsSearching = searchOn != "";
      Model.AllTasks = new ObservableCollection<TaskItem>();
      Model.ShowMessageNoTasksAvailable = !Model.ShowLoadingIndicator && _tasks.All(task => task.Status == TaskStatusEnum.Finished);
      AddUncompletedTasks(searchOn);
    }

    private void AddUncompletedTasks(string searchOn = "") {
      if (_tasks == null) return;
      var tasks = _tasks.Where(c => c.Status != TaskStatusEnum.Finished).ToArray();
      if (searchOn != "") {
        tasks = _tasks.Where(task => task.GetSearchableTaskString(_localLocationDataService.GetLocations()).Contains(searchOn.ToUpper(CultureInfo.InvariantCulture))).ToArray();
      }

      for (var i = 0; i < tasks.Length; i++) {
        AddUncompletedTask(i, tasks[i]);
      }
    }

    private void AddUncompletedTask(int index, YardOperatorTask task) {
      var rowBackgroundColor = Color.FromHex("FFFFFF");
      if (index % 2 == 0) {
        rowBackgroundColor = Color.FromHex("F6F6F6");
      }

      var leftIconChar = CalcLeftIconChar(task);
      var iconColor = CalcIconColor(task);
      var rightIconChar = CalcRightIconChar(task);

      var stepProgressLineStepsDone = task.TaskSteps.Count(c => c.IsDone).ToString();
      var stepProgressLineStepsTotal = task.TaskSteps.Count().ToString();

      Model.AllTasks.Add(new TaskItem {
        TaskIsFinished = false,
        TaskId = task.Id,
        LeftIconChar = leftIconChar,
        LeftIconColor = iconColor,
        TaskLine1 = task.GetTaskDisplayName(_localLocationDataService.GetLocations()),
        TaskLine2 = task.Template.Name,
        RightIconChar = rightIconChar,
        RightIconColor = iconColor,
        RowBackGroundColor = rowBackgroundColor,
        StepProgressLineStepsDone = stepProgressLineStepsDone,
        StepProgressLineStepsTotal = stepProgressLineStepsTotal,
        DisplayName = task.Asset?.Name ?? task.Visitor.Name
      });
    }

    private static char CalcRightIconChar(YardOperatorTask task) {
      switch (task.Status) {
        case TaskStatusEnum.Unassigned:
          return IconChar.For(IconsEnum.TaskListTaskIsUnassiged);
        case TaskStatusEnum.Assigned:
        case TaskStatusEnum.Started:
          return IconChar.For(IconsEnum.TaskListTaskStarted);
        default:
          return ' ';
      }
    }

    private static Color CalcIconColor(YardOperatorTask task) {
      switch (task.Status) {
        case TaskStatusEnum.Unassigned:
          return IconColor.For(IconsEnum.TaskListTaskIsUnassiged);
        case TaskStatusEnum.Assigned:
        case TaskStatusEnum.Started:
          return IconColor.For(IconsEnum.TaskListTaskStarted);
        default:
          return Color.Black;
      }
    }

    private static char CalcLeftIconChar(YardOperatorTask task) {
      if (task.TaskSteps.Any(c => c.FieldDefinitionType == FieldDefinitionType.MoveToLocation)) {
        return IconChar.For(IconsEnum.TaskListTaskIsMove);
      }
      else {
        return IconChar.For(IconsEnum.TaskListTaskIsInspection);
      }
    }
  }
}

I believe that this piece of code in the XAML is the culprit. More specific, the IsVisible property of the label. If I remove that, the exception does not seem to happen.

<Label
                    Grid.Row="1"
                    Grid.Column="1"
                    Grid.ColumnSpan="2"
                    FontSize="16"
                    HorizontalTextAlignment="Start"
                    LineBreakMode="TailTruncation"
                    Text="{Binding DisplayName}"
                    TextColor="{StaticResource PeripassBlack}"
                    VerticalOptions="StartAndExpand"
                    VerticalTextAlignment="Center"
                    IsVisible="{Binding Source={x:Reference tasksPage}, Path=BindingContext.Model.IsSearching}"
                    />

I have searched for some time now and tried different things but nothing seems to work. If you need more information, please do ask.

Upvotes: 2

Views: 2309

Answers (1)

nevermore
nevermore

Reputation: 15806

This issue has been fix in the latest version of Xamarin.forms 4.8.0.1687.

Any one who meet this issue please update your Xamarin.forms version.

Here are some relevant threads in the Github.

Cannot access a disposed object

Cannot access a disposed object FastRenderers.LabelRenderer

Upvotes: 2

Related Questions