MVVM Navigation Force Close Xamarin Forms - c#

I try using mvvm in my xamarin forms but i'm still litle bit confused with the navigation in each page, I Already Create Interface and NavigationService to handle all Navigation in my Xamarin Forms, there is no error code line but when i click the buton and try to navigate to other page it always crash. Here is some of my code
My Interface
namespace KGVC.Interfaces
{
public interface INavigationService
{
void NavigateToDashboard();
void NavigateToLogout();
void NavigateBack();
void gotoNews();
void goEvent();
void gotoKGCash();
void gotoCardCommnunity();
void gotoSetting();
void gotoNearbyLocation();
}
}
my navigationservice
namespace KGVC.Services
{
public class NavigationService : INavigationService
{
public void goEvent()
{
var currentPage = GetCurrentPage();
currentPage.Navigation.PushAsync(new EventPage());
}
public void gotoCardCommnunity()
{
var currentPage = GetCurrentPage();
currentPage.Navigation.PushAsync(new CardCommunityPage());
}
public void gotoKGCash()
{
var currentPage = GetCurrentPage();
currentPage.Navigation.PushAsync(new KGCashPage());
}
public void gotoNearbyLocation()
{
var currentPage = GetCurrentPage();
currentPage.Navigation.PushAsync(new StoreMaps());
}
public void gotoNews()
{
var currentPage = GetCurrentPage();
currentPage.Navigation.PushAsync(new RssFeedView());
}
public void gotoSetting()
{
var currentPage = GetCurrentPage();
currentPage.Navigation.PushAsync(new SettingPages());
}
public void NavigateBack()
{
throw new NotImplementedException();
}
public void NavigateToDashboard()
{
var currentPage = GetCurrentPage();
Application.Current.MainPage = new MainPage();
}
public void NavigateToLogout()
{
var currentPage = GetCurrentPage();
Application.Current.MainPage = new NewPageLogin();
}
private Page GetCurrentPage()
{
var currentPage = Application.Current.MainPage.Navigation.NavigationStack.LastOrDefault();
return currentPage;
}
}
}
my view model
public class GridMenuViewModel
{
public ICommand gotoNews { get; private set; }
public ICommand goEvent { get; private set; }
public ICommand gotoKGCash { get; private set; }
public ICommand gotoSetting { get; private set; }
public ICommand gotoNearbyLocation { get; private set; }
public GridMenuViewModel()
{
gotoNews = new Command(() =>
{
var navigationService = new NavigationService();
navigationService.gotoNews();
});
goEvent = new Command(() =>
{
var navigationService = new NavigationService();
navigationService.goEvent();
});
gotoKGCash = new Command(() =>
{
var navigationService = new NavigationService();
navigationService.gotoKGCash();
});
gotoSetting = new Command(() =>
{
var navigationService = new NavigationService();
navigationService.gotoSetting();
});
gotoNearbyLocation = new Command(() =>
{
var navigationService = new NavigationService();
navigationService.gotoNearbyLocation();
});
}
}
And my view
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
NavigationPage.HasNavigationBar="True"
NavigationPage.BackButtonTitle="False"
BindingContext="{Binding GridMenuViewModel, Source={StaticResource Locator}}"
xmlns:control="clr-namespace:Xamarin.Forms;assembly=Xamarin.Forms.CarouselView"
xmlns:local="clr-namespace:KGVC.Views.MainPages"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="KGVC.Views.MainPages.GridMenu"
Title="HOME"
>
<ContentPage.Content>
<StackLayout >
<StackLayout BackgroundColor="##CEB053">
<StackLayout HeightRequest="35" BackgroundColor="##CEB053" Orientation="Horizontal">
<Label FontAttributes="Italic" TextColor="Black" Margin="9" Text="Hello," FontSize="15"/>
<Label TextColor="Black" Margin="9" Text="John Doe" FontSize="15" FontAttributes="Bold"/>
</StackLayout>
<StackLayout Padding="0" HeightRequest="30" BackgroundColor="#E3E6E3" Orientation="Horizontal">
<Image Margin="5" Source="ic_logo.png"/>
<Label Text="Points" Margin="5" FontSize="13" TextColor="Black"/>
</StackLayout>
</StackLayout>
<StackLayout HeightRequest="220" VerticalOptions="StartAndExpand">
<control:CarouselView HeightRequest="185" ItemsSource="{Binding MyDataSource}" Position="{Binding Position, Mode=TwoWay}">
<control:CarouselView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Image}"/>
</DataTemplate>
</control:CarouselView.ItemTemplate>
</control:CarouselView>
<local:CarouselIndicators IndicatorHeight="9" IndicatorWidth="9" UnselectedIndicator="unselected_circle.png" SelectedIndicator="selected_circle.png" Position="{Binding Position}" ItemsSource="{Binding MyDataSource}" />
</StackLayout>
<ScrollView IsClippedToBounds="True" VerticalOptions="StartAndExpand" Orientation="Vertical" >
<Grid x:Name="controlGrid" VerticalOptions="StartAndExpand" HeightRequest="370" Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="0" />
<RowDefinition Height="100" />
<RowDefinition Height="100" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="110" />
<ColumnDefinition Width="110" />
<ColumnDefinition Width="110" />
</Grid.ColumnDefinitions>
<StackLayout Orientation="Vertical" Grid.Row="1" Grid.Column="0" >
<Button Image="ic_account.png" Margin="5"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="MY ACCOUNT" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="1" Grid.Column="1">
<Button Margin="5" Command="{Binding gotoCardCommunity}" Image="ic_card.png"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="CARD" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="1" Grid.Column="2">
<Button Margin="5" Command="{Binding goEvent}" Image="ic_event"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="PROMO" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Grid.Row="2" Grid.Column="0" Orientation="Vertical">
<Button Margin="5" Command="{Binding gotoNearbyLocation}" Image="ic_store"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="STORE LOCATIONS" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="2" Grid.Column="1">
<Button Margin="5" Command="{Binding gotoNews}" Image="ic_news"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="NEWS" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Grid.Row="2" Grid.Column="2" Orientation="Vertical">
<Button Margin="5" Command="{Binding gotoKGCash}" Image="ic_kgcash"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="E-WALLET" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="3" Grid.Column="0">
<Button Margin="5" Image="ic_ecommerce"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="E-COMMERCE" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="3" Grid.Column="1">
<Button Margin="5" Command="{Binding gotoSetting}" Image="ic_pointsummary.png"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="POINT SUMMARY" HorizontalOptions="Center"/>
</StackLayout>
<StackLayout Orientation="Vertical" Grid.Row="3" Grid.Column="2">
<Button Margin="5" Command="{Binding gotoSetting}" Image="ic_setting"
Style="{StaticResource plainButton}" />
<Label FontSize="12" Text="SETTINGS" HorizontalOptions="Center"/>
</StackLayout>
</Grid>
</ScrollView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
i already try change the navigation service to use pushmodalasync, make the navigation async but still crash, Anyone can help me ? and i'm not using prism , mvvmlight and other 3rd party mvvm nuget

It depends on your MainPage. Did you check if GetCurrentPage() actually returns something?
Try to change the GetCurrentPage() to:
Page GetCurrentPage() =>
Application.Current.MainPage.Navigation?.NavigationStack?.LastOrDefault() ??
Application.Current.MainPage;
Another problems that I spotted:
1. C# naming conventions are different from Java. Method names should start with a capital letter. Currently you have a pure mix.
2. Initialising the BindingContext in XAML the way you did will create the ViewModel twice due to a bug. Change it to:
<ContentPage
xmlns:vm="your-namespace.vm"
...>
<ContentPage.BindingContext>
<vm:GridMenuViewModel />
</ContentPage.BindingContext>
</ContentPage>
3. No need to recreate the NavigationService for each command. Reuse it in your ViewModel.
4. You have some corrupted XAML:
<StackLayout BackgroundColor="##CEB053">
Fix the hex code. Generally speaking you could enable XAMLC so you would get notified about XAML errors while building your code.
5. In order to use PushAsync your MainPage should be wrapped by NavigationPage.
6. You need to await async code execution:
public async Task GoToCardCommnunity()
{
var currentPage = GetCurrentPage();
await currentPage.Navigation.PushAsync(new CardCommunityPage());
}
Check over the list above and pay attention to the application output and exceptions.

Related

Button Clicked Event inside a Collection View Xamarin Forms

I have a collectionView that gets the item source from the backend based on the model
public partial class Post
{
public int Id {get; set;}
public int Upvotes {get; set;}
public string Text {get; set;}
}
The collectionView looks like this:
<CollectionView x:Name="collectionView" Margin="10" SelectionMode="Single" SelectionChanged="collectionView_SelectionChanged">
<CollectionView.ItemTemplate>
<DataTemplate>
<Frame HasShadow="True" CornerRadius="20" BorderColor="DarkGray">
<StackLayout Orientation="Vertical" Padding="0" Spacing="0" >
<StackLayout Orientation="Vertical">
<StackLayout Orientation="Horizontal">
<Label Text="Text:" FontAttributes="Bold" HorizontalOptions="Start" VerticalOptions="Center" FontSize="Body" TextColor="#000000"/>
<Label Text="{Binding Text}" HorizontalOptions="Start" VerticalOptions="Center" FontSize="Body" TextColor="#000000"/>
</StackLayout>
<Grid BackgroundColor="White" Margin="2">
<StackLayout>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="auto" />
<ColumnDefinition Width="auto"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" x:Name="btnUpvote" Clicked="btnUpvote_Clicked" Text="Upvote" TextColor="Green" CornerRadius="50" HeightRequest="40" HorizontalOptions="Start" VerticalOptions="Center" BackgroundColor="#1110"/>
<StackLayout Grid.Column="1" Orientation="Horizontal">
<Label Text="Upvotes:" TextColor="Black" FontSize="Body" FontAttributes="Bold" VerticalOptions="Center"/>
<Label Text="{Binding Upvotes}" HorizontalOptions="Start" VerticalOptions="Center" FontSize="Body" TextColor="#000000"/>
</StackLayout>
</Grid>
</StackLayout>
</Grid>
</StackLayout>
</Frame>
</DataTemplate>
</CollectionView.ItemTemplate>
I want to click on the Upvote button so I could call an API to increase the number of upvotes, but I need the Id from the selected collectionView Item. I am not sure how to get the Id (without clicking on the collection view, only clicking the Upvote button) before calling the API that needs the Id.
To complete my remark above. I have a button in my xaml that looks like this:
<Button Text="Delete"
Command="{Binding Path=BindingContext.Delete, Source={x:Reference SongsCollectionView}}"
CommandParameter="{Binding .}"
Grid.Column="3" Grid.Row="0" StyleClass="Delete"/>
It references the collection it is inside (in your case that would be the 'collectionView').
Now in my case the program was written with MvvmCross. In the init of the SongsCollectionView the following code is present for the Delete.
public SongsViewModel(IMvxNavigationService navigationService) : base(navigationService)
{
Delete = new MvxCommand<Song>(
execute: (song) =>
{
// Code for deleting song is in here.
});
}
public ICommand Delete { get; set; }
Simply replace the MvxCommand by Command and it should work.
in addition to using a Command, you can also do this with a simple event handler by using the BindingContext
void btnUpvote_Clicked(object sender, EventArgs args)
{
Button btn = (Button)sender;
var item = (Post)btn.BindingContext;
}

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.
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

How to hide a part of the page,after the action of the command?

I have a listview in the content view,and I want to after refreshing hide a part of the page.Please help me to it.I tried to make a swipe but listview conflict with it.so I decided to try make with refresh
<ContentView.Content>
<controls:CustomFrame CornerRadius="25,25,0,0" Margin="0" Padding="10" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<StackLayout Padding="0">
<BoxView HorizontalOptions="Center" WidthRequest="40" HeightRequest="7" BackgroundColor="Gray" CornerRadius="15" />
<!-- <StackLayout.GestureRecognizers>
<SwipeGestureRecognizer Direction="Up" Command="{Binding RefreshCommand}" ></SwipeGestureRecognizer>
</StackLayout.GestureRecognizers>-->
<ListView ItemsSource="{Binding MyPins}" RowHeight="100" x:Name="ListPlaces" IsPullToRefreshEnabled="True" RefreshCommand="{Binding RefreshCommand}"
IsRefreshing="{Binding IsRefreshing}"
SelectionMode="None">
<ListView.ItemTemplate >
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Frame CornerRadius="10" BackgroundColor="LightBlue" Padding="10">
<StackLayout Orientation="Vertical" Padding="0">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer CommandParameter="{Binding .}" Command="{Binding BindingContext.CallPlace, Source={x:Reference ListPlaces}}" ></TapGestureRecognizer>
</StackLayout.GestureRecognizers>
<Label x:Name="NameOfPlace" Text="{Binding Name}" TextColor="#2D78FD" FontSize="14" FontFamily="Robobo"/>
<Label x:Name="AdressOfPlace" Text="{Binding Address}" TextColor="#616161" FontSize="12" FontFamily="Robobo"/>
<StackLayout Orientation="Horizontal">
<Label x:Name="TimeWork" VerticalOptions="Center" Text="Open until - " TextColor="#616161" FontSize="12" FontFamily="Robobo"/>
<Label x:Name="TimeWork1" VerticalOptions="Center" Text="{Binding Opened}" TextColor="#616161" FontSize="12" FontFamily="Robobo"/>
<Image Source="openIcon" VerticalOptions="Center" />
<Button HeightRequest="24" VerticalOptions="Center" Padding="0,-3,0,0" WidthRequest="92" HorizontalOptions="EndAndExpand" FontSize="14" CornerRadius="45" BackgroundColor="#2D78FD" TextColor="White" Text="Call up"/>
</StackLayout>
</StackLayout>
</Frame>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</controls:CustomFrame>
</ContentView.Content>
WHAT I WANT TO DO
Since you had used MVVM , there are many ways which can implements .
Option 1 :
We could set the IsVisible property of the ViewCell
in xaml
Define the property in the model
public class YourModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
bool isVisible;
public bool IsVisible
{
get
{
return isVisible;
}
set
{
if(value!=isVisible)
{
isVisible = value;
OnPropertyChanged("IsVisible");
}
}
//other property like name...
}
In ViewModel
CallPlace = new Command((org)=> {
YourModel model = org as YourModel;
model.isVisible = false;
});
Option 2
You could remove the item from MyPins
CallPlace = new Command((org)=> {
YourModel model = org as YourModel;
MySource.Remove(model);
});

Xamarin Forms Command Binding inside ListView is not working

i'm trying to bind a command to a button inside a listView, but without success. I follow all other answers posted here, like this one:
Xamarin Forms Button Command binding inside a ListView
The actual result is that nothing happens. A thing that i notice is that visual studio, when i type after x:Reference suggests me just GridWebcam, like if it doesn't see other reference elements. What can i do?
Here my code:
<ContentPage
...
x:Name="WebcamList">
<ContentPage.Resources>
...
<ContentPage.Content>
<ListView ItemsSource="{Binding ListOfWebcam}"
SeparatorVisibility="None"
CachingStrategy="RecycleElement"
RowHeight="250"
VerticalOptions="FillAndExpand"
x:Name="ListWebcam">
<ListView.Header>
<StackLayout x:Name="HeaderStackLayout"
Padding="5,25,0,30"
Orientation="Horizontal"
HorizontalOptions="FillAndExpand">
<Label x:Name="LabelHeader"
Text="Webcam:"
FontSize="Large"
FontAttributes="Bold"
TextColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="Center"
HorizontalOptions="Start" Margin="10,0,0,0"/>
</StackLayout>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<controls:ExtendedViewCell IsEnabled="False">
<controls:ExtendedViewCell.View>
<Grid x:Name="GridWebcam">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Frame Grid.Column="1"
Grid.RowSpan="2"
CornerRadius="20"
BackgroundColor="{x:Static statics:Palette.PrimaryColor}"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
HasShadow="True"
Margin="5,10">
<StackLayout>
<Label Text="{Binding t_str_vid,Converter={StaticResource WebcamNameConverter}}"
FontSize="Medium"
TextColor="White"
FontAttributes="Bold"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
</Label>
<Label TextColor="White"
FontSize="Medium"
Text="{Binding direzione,Converter={StaticResource DirectionToStringConverter}}"/>
<StackLayout Orientation="Horizontal">
<ffimageloading:CachedImage LoadingPlaceholder="Rolling.gif"
DownsampleToViewSize="False"
VerticalOptions="FillAndExpand"
HorizontalOptions="StartAndExpand"
Source="{Binding image1}"/>
<iconize:IconButton Text="fas-play-circle"
FontSize="50"
HorizontalOptions="EndAndExpand"
VerticalOptions="EndAndExpand"
TextColor="White"
Command="{Binding BindingContext.OpenVideoWebcamCommand, Source={x:Reference WebcamList}}"
CommandParameter="{Binding .}"
BackgroundColor="Transparent"/>
</StackLayout>
</StackLayout>
</Frame>
</Grid>
</controls:ExtendedViewCell.View>
</controls:ExtendedViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
```
public class WebcamListViewModel : BaseViewModel
{
public ICommand OpenVideoWebcamCommand { set; get; }
private List<Webcam> _ListOfWebcam { get; set; }
public List<Webcam> ListOfWebcam
{
get { return _ListOfWebcam; }
set
{
_ListOfWebcam = value;
OnPropertyChanged();
}
}
private Task DownloadFramesTask;
CancellationTokenSource tokenSourceDownloadFrames = new CancellationTokenSource();
CancellationToken cancellationTokenDownloadFrames;
public WebcamListViewModel(INavigationService navigationService, IApiAutostradeManagerFactory apiAutostradeManagerFactory) : base(navigationService,apiAutostradeManagerFactory)
{
OpenVideoWebcamCommand = new Command<Webcam>(async (webcam) => {
await navigationService.NavigateAsync(Locator.WebcamVideoPopUpPage);
Messenger.Default.Send(new InfoWebcamVideoMessage(webcam.c_mpr, webcam.c_uuid, webcam.t_str_vid));
});
}
Well it could be related to this mysterious controls:ExtendedViewCell of yours :)
Also did you disable the ListView selection: <ListView ... SelectionMode="None" /> ?
As Roubachof said that I don't know if it is related to controls:ExtendedViewCell,please check if you have binding BindingContext, then you can take a look the following code:
<StackLayout>
<ListView x:Name="listview1" ItemsSource="{Binding persons}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal">
<Label Text="{Binding Id}" />
<Label Text="{Binding name}" />
<Button
Command="{Binding BindingContext.command, Source={x:Reference listview1}}"
CommandParameter="{Binding Id}"
Text="Delete item" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public partial class Page1 : ContentPage
{
public ObservableCollection<person> persons { get; set; }
public RelayCommand1 command { get; set; }
public Page1 ()
{
InitializeComponent ();
persons = new ObservableCollection<person>();
for(int i =0;i<20;i++)
{
person p = new person()
{
Id = i,
name = "cherry" + i
};
persons.Add(p);
command = new RelayCommand1(obj => method1((int)obj));
}
this.BindingContext = this;
}
public void method1(int Id)
{
persons.RemoveAt(Id);
//IEnumerable<person> list = persons.Where(x => x.Id == Id);
//foreach (person m in list)
//{
//}
}
}
public class person
{
public int Id { get; set; }
public string name { get; set; }
}

INotifyPropertyChanged ListView

I am new to Xamarin Forms and trying to implement Infinite Loop Functionality in my app. The sample code that i followed is working fine and i have managed to integrate it into my app successfully.
The problem is that i am unable to find out how to change the source of the listview from the code.
I intend to have buttons above my listview (As in the following Image) and upon click the source of the listView should change.
This is how my code looks like
<ContentPage.BindingContext>
<local:MainViewModel />
</ContentPage.BindingContext>
<StackLayout>
<ListView x:Name="tyres_listview" ItemsSource="{Binding Items}"
HasUnevenRows="True" SeparatorVisibility="None" >
<ListView.Behaviors>
<extended:InfiniteScrollBehavior IsLoadingMore="{Binding IsBusy}" />
</ListView.Behaviors>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout>
<Grid Margin="10" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.25*"></ColumnDefinition>
<ColumnDefinition Width="0.75*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<StackLayout Grid.Column="0" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand" Margin="5,5,5,10">
<Image Source="{Binding image_url}" >
</Image>
</StackLayout>
<StackLayout Grid.Column="1" Spacing="0" >
<Label Text="{Binding name}" FontAttributes="Bold" FontSize="Small" Margin="0,5,5,0" VerticalOptions="Center" ></Label>
<Label Text="{Binding brand}" VerticalOptions="Center" FontSize="Micro" ></Label>
<Label Text="{Binding item_id}" VerticalOptions="Center" FontSize="Micro" ></Label>
<StackLayout Orientation="Horizontal" x:Name="sl_db" >
<Image Source="fuel.png" ></Image>
<Label Text="{Binding fuel_type}"></Label>
<Image Source="weather.png"></Image>
<Label Text="{Binding wheather_type }"></Label>
<Image Source="volume.png" ></Image>
<Label Text="{Binding noise}"></Label>
<Label Text="dB"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Image></Image>
<Label Text="{Binding rated_count }"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Price: " VerticalOptions="Center"></Label>
<Label Text="{Binding price }" VerticalOptions="Center" TextColor="Green"></Label>
<Label Text=" EUR" VerticalOptions="Center"></Label>
</StackLayout>
<StackLayout Orientation="Horizontal">
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_1" >
</TapGestureRecognizer>
</StackLayout.GestureRecognizers>
<StackLayout BackgroundColor="Red" Orientation="Horizontal" Margin="5" >
<Image Source="shoppingcart.png" Margin="10,0,0,0"></Image>
<Label Text="Add to Cart" VerticalOptions="Center" HorizontalOptions="EndAndExpand" Margin="0,0,10,0" ></Label>
</StackLayout>
<Image x:Name="button_info" Source="info.png" >
<Image.GestureRecognizers>
<TapGestureRecognizer Tapped="button_info_Clicked"></TapGestureRecognizer>
</Image.GestureRecognizers>
</Image>
</StackLayout>
</StackLayout>
</Grid>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Footer>
<Grid Padding="6" IsVisible="{Binding IsBusy}">
<!-- set the footer to have a zero height when invisible -->
<Grid.Triggers>
<Trigger TargetType="Grid" Property="IsVisible" Value="False">
<Setter Property="HeightRequest" Value="0" />
</Trigger>
</Grid.Triggers>
<!-- the loading content -->
<Label Text="Loading..." TextColor="DeepPink" FontSize="20" FontAttributes="Bold" VerticalOptions="Center" HorizontalOptions="Center" />
</Grid>
</ListView.Footer>
</ListView>
<Button Clicked="button_Change_Order_Clicked"></Button>
</StackLayout>
public class MainViewModel : INotifyPropertyChanged
{
private bool _isBusy;
private const int PageSize = 10;
readonly DataService _dataService = new DataService();
public InfiniteScrollCollection<Product_Search> Items { get; }
public bool IsBusy
{
get => _isBusy;
set
{
_isBusy = value;
OnPropertyChanged();
}
}
public MainViewModel()
{
Items = new InfiniteScrollCollection<Product_Search>
{
OnLoadMore = async () =>
{
IsBusy = true;
// load the next page
var page = Items.Count / PageSize;
var items = await _dataService.GetItemsAsync(page, PageSize);
IsBusy = false;
// return the items that need to be added
return items;
},
OnCanLoadMore = () =>
{
return Items.Count < 44;
}
};
DownloadDataAsync();
}
private async Task DownloadDataAsync()
{
var items = await _dataService.GetItemsAsync(pageIndex: 0, pageSize: PageSize);
Items.AddRange(items);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
Any help would be of great importance.
Your ListView.Items property is already bound to your MainViewModel.Items property, a PropertyChanged event needs to be triggered to signal a change on the property value (corresponding to the property itself or its content if InfiniteScrollCollection<> is an Observable collection).
When you would want to replace the Items source you can give it a new value, signal it has changed and your ListView might be refreshed:
private InfiniteScrollCollection<Product_Search> _items;
public InfiniteScrollCollection<Product_Search> Items
{
get { return _items; }
set
{
_items = value;
OnPropertyChanged();
}
}

Categories

Resources