Reputation: 1063
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
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