INotifyPropertyChanged ListView - c#

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();
}
}

Related

Xamarin.Forms - Adjusting height of CollectionView to be minimum size to fit children

I have a CollectionView with a few items in it. I'm trying to adjust the size of the CollectionView to be just big enough to fit all of its children. Right now, it's much larger than the amount of children it has.
The Blue color represents the size of the CollectionView. As you can see, it's well beyond the size of it's children. I'd like it to fit them perfectly, or at the very least be closer to the same size.
I don't have any height requests on any of the elements on the page, including the CollectionView.
Here's my code. It's not particularly pretty at the moment, but it's a work in progress.
<StackLayout>
<CollectionView x:Name="assessmentsCollectionView"
BackgroundColor="Blue">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Spacing="10"
Padding="5">
<Frame CornerRadius="5"
Padding="0"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal">
<Frame Padding="5"
CornerRadius="0"
WidthRequest="50">
<Label Text="{Binding TypeLetter}"
TextColor="#37474f"
FontSize="24"
VerticalTextAlignment="Center"
HorizontalTextAlignment="Center"/>
</Frame>
<StackLayout Padding="10">
<Label Text="{Binding Name}"
TextColor="Black"
FontSize="24"/>
<StackLayout Orientation="Horizontal">
<Image Source="calendarIcon.png"
WidthRequest="12"
HeightRequest="12"/>
<Label Text="{Binding Date}"
FontSize="12"
TextColor="Gray"/>
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
I changed CollectionView to FlexLayout with BindableLayout.ItemsSource and BindableLayout.ItemTemplate
What was previously
<CollectionView.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
What was done
<FlexLayout Direction="Column"
x:Name="MessagesList"
AutomationId="MessagesList"
BindableLayout.ItemsSource="{Binding Messages}" >
<BindableLayout.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
For me works well, no need to set Height for item or FlexLayout, all are dynamic
If you have little rows in Collectionview, you can set a value to collectionView.HeightRequest. when item increase, the height will increase as well.
I create a property called.RowHeigth. If I add item in the CollectionView(with AddCommand), RowHeigth will increase.
<StackLayout>
<CollectionView
x:Name="assessmentsCollectionView"
BackgroundColor="Blue"
HeightRequest="{Binding rowHeigth}"
ItemsSource="{Binding letters}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Padding="5" Spacing="10">
<Frame
Padding="0"
CornerRadius="5"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal">
<Frame
Padding="5"
CornerRadius="0"
WidthRequest="50">
<Label
FontSize="24"
HorizontalTextAlignment="Center"
Text="{Binding TypeLetter}"
TextColor="#37474f"
VerticalTextAlignment="Center" />
</Frame>
<StackLayout Padding="10">
<Label
FontSize="24"
Text="{Binding Name}"
TextColor="Black" />
<StackLayout Orientation="Horizontal">
<Image
HeightRequest="12"
Source="c1.png"
WidthRequest="12" />
<Label
FontSize="12"
Text="{Binding Date}"
TextColor="Gray" />
</StackLayout>
</StackLayout>
</StackLayout>
</Frame>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<Button
x:Name="btn1"
Command="{Binding AddCommand}"
Text="btn1" />
</StackLayout>
public partial class Page4 : ContentPage
{
public Page4()
{
InitializeComponent();
this.BindingContext = new letterviewmodel(); ;
}
}
public class letterviewmodel: INotifyPropertyChanged
{
public ObservableCollection<lettermodel> letters { get; set; }
private int _rowHeigth;
public int rowHeigth
{
get { return _rowHeigth; }
set
{
_rowHeigth = value;
RaisePropertyChanged("rowHeigth");
}
}
public ICommand AddCommand { protected set; get; }
public letterviewmodel()
{
letters = new ObservableCollection<lettermodel>()
{
new lettermodel(){TypeLetter="A",Name="letter 1",Date="2021-01-01"},
new lettermodel(){TypeLetter="B",Name="letter 2",Date="2021-01-01"},
new lettermodel(){TypeLetter="C",Name="letter 3",Date="2021-01-01"}
};
rowHeigth = letters.Count * 100 ;
AddCommand = new Command<lettermodel>(async (key) => {
letters.Add(new lettermodel() { TypeLetter = "D", Name = "test letter ", Date = "2021-01-01" });
rowHeigth = letters.Count * 100 ;
});
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class lettermodel
{
public string TypeLetter { get; set; }
public string Name { get; set; }
public string Date { get; set; }
}
Don't forget toimplement INotifyPropertyChanged interface, to inotify data update.

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: ObservableCollection does't automatically update ListView

I have a ListView bounded to an ObservableCollection in the ViewModel.
In initialization the ListView items are displayed perfectly.
However, when I try to update a single value of an item of ObservableCollection at run-time, the linked item in the listview does not update automatically. It updates only if I scroll the listView. Why does it behave like this?
Here's the code:
XAML
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame Style="{StaticResource frameListView}" >
<StackLayout Margin="-15">
<Label Text="{Binding Articolo.Descrizione}"
Style="{StaticResource labelDescrizioneStyle}" />
<StackLayout Orientation="Horizontal"
HorizontalOptions="End" VerticalOptions="Center">
<Button x:Name="removeButton"
VerticalOptions="Center" HorizontalOptions="Center"
Text="-"
Font="20"
WidthRequest="45" FontAttributes="Bold"
Style="{StaticResource buttonNeutroStyle}"
Command="{Binding Source={x:Reference mieiAcquistiStack}, Path=BindingContext.AggiungiCommand}"
CommandParameter="{Binding .}" />
<StackLayout HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" >
<Label Text="{Binding QtaEdit}"
TextColor="Black"
FontSize="18" FontAttributes="Bold"
WidthRequest="40"
HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
VerticalOptions="FillAndExpand"/>
</StackLayout>
<Button x:Name="addButton"
VerticalOptions="Center" HorizontalOptions="Center"
Text="+"
WidthRequest="45" FontAttributes="Bold"
Style="{StaticResource buttonNeutroStyle}"
Command="{Binding Source={x:Reference mieiAcquistiStack}, Path=BindingContext.AggiungiCommand}"
CommandParameter="{Binding .}" />
</StackLayout>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
ViewModel
public static ObservableCollection<RigaStoricoModel> acquistiList;
public ObservableCollection<RigaStoricoModel> AcquistiList
{
get { return acquistiList; }
set
{
if (acquistiList != value)
{
acquistiList = value;
OnPropertyChanged();
}
}
}
private void AggiungiArticolo(RigaStoricoModel prodotto, ParametriUM parametriUM)
{
double esistenzaUMPredef = parametriUM.EsistenzaUMPredef.GetValueOrDefault(0);
if (esistenzaUMPredef > 0)
{
double qtaMinima = parametriUM.QtaMinima.GetValueOrDefault(1);
if (prodotto.QtaEdit + qtaMinima <= esistenzaUMPredef)
{
prodotto.QtaEdit += qtaMinima; // <-- here the update not working
}
}
Do you want to achieve the result like following GIF?
If so, you should achieve the INotifyPropertyChanged interface in your RigaStoricoModel as Silvermind's said.
Here is MyViewModel.cs code.
public class RigaStoricoModel: INotifyPropertyChanged
{
private double _qtaEdit;
public double QtaEdit
{
set
{
_qtaEdit = value;
OnPropertyChanged("QtaEdit");
}
get => _qtaEdit;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I used AggiungiCommand to make a test(decrease or increase).
public class MyViewModel
{
public static ObservableCollection<RigaStoricoModel> acquistiList;
public ObservableCollection<RigaStoricoModel> AcquistiList
{
get { return acquistiList; }
set
{
if (acquistiList != value)
{
acquistiList = value;
// OnPropertyChanged();
}
}
}
public ICommand AggiungiCommand { protected set; get; }
public ICommand AggiungiCommand2 { protected set; get; }
// public int MyProperty { get; set; }
public MyViewModel()
{
AcquistiList = new ObservableCollection<RigaStoricoModel>();
AcquistiList.Add(new RigaStoricoModel() { QtaEdit=0.28 });
AcquistiList.Add(new RigaStoricoModel() { QtaEdit = 0.38 });
AcquistiList.Add(new RigaStoricoModel() { QtaEdit = 0.48 });
AcquistiList.Add(new RigaStoricoModel() { QtaEdit = 0.58 });
AcquistiList.Add(new RigaStoricoModel() { QtaEdit = 0.68 });
AggiungiCommand2=new Command(async (key) =>
{
RigaStoricoModel model = key as RigaStoricoModel;
model.QtaEdit += 0.1;
});
AggiungiCommand = new Command(async (key) =>
{
RigaStoricoModel model= key as RigaStoricoModel;
model.QtaEdit -= 0.1;
});
}
}
}
Here is layout.xaml(I do not have this style, for testing,I delete them and adjust this layout).
<StackLayout>
<!-- Place new controls here -->
<ListView ItemsSource="{Binding AcquistiList}" x:Name="mieiAcquistiStack" HasUnevenRows="True" >
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Frame >
<StackLayout Margin="-15" HorizontalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand">
<Label Text="{Binding Articolo.Descrizione}"
/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="End" VerticalOptions="Center">
<Button x:Name="removeButton"
VerticalOptions="Center" HorizontalOptions="Center"
Text="-"
Font="20"
WidthRequest="45" FontAttributes="Bold"
Command="{Binding Source={x:Reference mieiAcquistiStack}, Path=BindingContext.AggiungiCommand}"
CommandParameter="{Binding .}" />
<StackLayout HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand" >
<Label Text="{Binding QtaEdit}"
TextColor="Black"
FontSize="18" FontAttributes="Bold"
WidthRequest="40"
HorizontalTextAlignment="Center" VerticalTextAlignment="Center"
VerticalOptions="FillAndExpand"/>
</StackLayout>
<Button x:Name="addButton"
VerticalOptions="Center" HorizontalOptions="Center"
Text="+"
WidthRequest="45" FontAttributes="Bold"
Command="{Binding Source={x:Reference mieiAcquistiStack}, Path=BindingContext.AggiungiCommand2}"
CommandParameter="{Binding .}" />
</StackLayout>
</StackLayout>
</Frame>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
Here is layout background code.
public MainPage()
{
InitializeComponent();
this.BindingContext = new MyViewModel();
}

Xamarin forms Activity Indicator Not Showing on Button click Even when Binding is true

I have a Activity Indicator and have no issues with how it looks or anything like that, i just can't get it to to display on the button click.
There's a Lengthy Process that i need to go threw when Checking items out on the cart.
The Method Structure:
Button Clicked => Api Calls
=> await IsinStock()
=> Fetch Products
=> await SingleCheck() || await VariableCheck()
=> No Errors => AddOrder || Errors Display Error
My Indicators are being set to Active before API calls and Ends after checks are complete and it returns to add or show errors.
But it's just not displaying.
<?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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
xmlns:o="clr-namespace:Octane.Xamarin.Forms.VideoPlayer;assembly=Octane.Xamarin.Forms.VideoPlayer"
xmlns:local="clr-namespace:Ecombeta"
xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
x:Class="Ecombeta.Views.Cart">
<ContentPage.Content>
<AbsoluteLayout>
<Grid
RowSpacing="0"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!--My Beautiful Ui Mark up here-->
</Grid>
<!--Loading Indicator-->
<AbsoluteLayout IsVisible="{Binding running}" AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1">
<BoxView
BackgroundColor="#80000000"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0,0,1,1" />
<StackLayout
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="0.5,0.5,-1,-1">
<Frame Padding="20,15"
CornerRadius="7"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand"
BackgroundColor="Black"
HasShadow="false">
<StackLayout VerticalOptions="Center"
HorizontalOptions="Center">
<ActivityIndicator
IsRunning="{Binding running}"
HorizontalOptions="Center"
VerticalOptions="Center"
Color="White" />
<Label Text="{Binding LoadingIndicatorMessage}"
x:Name="lblLoadingText"
HorizontalOptions="Center"
VerticalOptions="Center"
TextColor="White" />
</StackLayout>
</Frame>
</StackLayout>
</AbsoluteLayout>
<StackLayout Padding="5" AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All" BackgroundColor="White">
<ListView x:Name="cartView"
HasUnevenRows="True"
SeparatorColor="Black"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand"
SeparatorVisibility="Default"
IsPullToRefreshEnabled="True"
ItemSelected="EvetClicked">
<ListView.Resources>
<ResourceDictionary>
<local:BgConverter x:Key="BgConverter" />
</ResourceDictionary>
</ListView.Resources>
<ListView.Header>
<Label Text="Shopping List" HorizontalOptions="Center" VerticalOptions="Center"
HorizontalTextAlignment="Center" Margin="0,0,0,15" TextColor="Black"
FontAttributes="Bold" FontSize="Title" />
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<StackLayout Orientation="Vertical">
<Label TextColor="Black" x:Name="something" HorizontalOptions="CenterAndExpand"
Text="{Binding ProductName}" FontSize="Subtitle" />
<ffimageloading:CachedImage
HeightRequest="150"
WidthRequest="150"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
DownsampleToViewSize="true"
Source="{Binding ImgSource}" />
<Label IsVisible="{Binding _virtual}" HorizontalTextAlignment="Center"
TextColor="Black">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding CartAtribKey }" FontAttributes="Bold" />
<Span Text="{Binding CartAtribValue , StringFormat=' {0}' }"
FontSize="Small" />
</FormattedString>
</Label.FormattedText>
</Label>
<Label IsVisible="{Binding _virtual}" HorizontalTextAlignment="Center"
TextColor="Black">
<Label.FormattedText>
<FormattedString>
<Span Text="{Binding CartAtribKey1 }" FontAttributes="Bold" />
<Span Text="{ Binding CartAtribValue1, StringFormat=' {0}'}"
FontSize="Small" />
</FormattedString>
</Label.FormattedText>
</Label>
<!--<Label HorizontalOptions="EndAndExpand" VerticalOptions="StartAndExpand" Text="{Binding PId, StringFormat='SKU {0:F0}'}" FontSize="Medium"></Label> -->
<Label FontSize="Large" VerticalOptions="CenterAndExpand" TextColor="Black"
HorizontalOptions="CenterAndExpand"
Text="{Binding TotalDynamicPrice, StringFormat='Total R:{0,5:#,0.00}' }"
FontAttributes="Bold" />
<Label HorizontalOptions="CenterAndExpand" TextColor="Black"
FontAttributes="Bold"
Text="{Binding Source={x:Reference stepper}, Path=Value, StringFormat='Quantity {0:F0}'}"
FontSize="Medium" />
<StackLayout Orientation="Horizontal">
<ImageButton HorizontalOptions="Center" VerticalOptions="Center"
HeightRequest="30" WidthRequest="30"
Source="https://mm-app.co.za/wp-content/uploads/2020/01/icons8-remove-64.png"
BindingContext="{Binding PId}" Clicked="Removevalue_Clicked" />
<Stepper x:Name="stepper" Maximum="{Binding StockQuantity}"
Value="{Binding ProductQuantity}"
Minimum="{Binding MinQ}"
ClassId="{Binding PId}"
TabIndex="{Binding VariationId}"
HorizontalOptions="CenterAndExpand"
VerticalOptions="CenterAndExpand"
Increment="{Binding IncrementQ}"
ValueChanged="stepper_ValueChanged" />
</StackLayout>
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<StackLayout Padding="0" Orientation="Horizontal" BackgroundColor="White">
<Button Margin="2" TextColor="white" BorderColor="#0088d3" BackgroundColor="#0088d3"
CornerRadius="10" Padding="10" VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" Text="Buy Now!" Clicked="ImageButton_Clicked" />
</StackLayout>
</StackLayout>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
private async void ImageButton_Clicked(object sender, EventArgs e)
{
running = true;
try
{
//You cant checkout if your not logged in There are no Guest Checkouts(I can But would rather not)
if (Users.LoggedIn && _spamClick == false)
{
if (_orderlineitems == null)
_orderlineitems = new List<OrderLineItem>();
RestAPI rest = new RestAPI("http://xxxx/wp-json/wc/v2/","xxxxxxxxx","cs_xxxxxxxxxxx");
var wc = new WCObject(rest);
await IsInStock();
}
running = false;
}
(...)
}
public partial class Cart : ContentPage, INotifyPropertyChanged
private bool _running;
public bool running
{
get => _running;
set
{
if (_running == value)
return;
_running = value;
RaisePropertyChanged();
}
}
Any Ideas?
According to your description, I remember you posted a similar question a few days ago, but you deleted this question.
You said that you wanted to display ActivityIndicator when Button click, I test your code and find that there are two StackLayouts, one contains ActivityIndicator, another contains ListView, I suggest you can swap the positions of two stacklayouts, like this:
<AbsoluteLayout>
<StackLayout
Padding="5"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="White">
<ListView
x:Name="cartView"
HasUnevenRows="True"
HorizontalOptions="FillAndExpand"
IsPullToRefreshEnabled="True"
ItemsSource="{Binding products}"
SeparatorColor="Black"
SeparatorVisibility="Default"
VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Vertical">
<Label
x:Name="something"
HorizontalOptions="CenterAndExpand"
Text="{Binding ProductName}"
TextColor="Black" />
<Image
HeightRequest="150"
HorizontalOptions="CenterAndExpand"
Source="{Binding ImgSource}"
VerticalOptions="CenterAndExpand"
WidthRequest="150" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button
x:Name="getproduct"
Clicked="Getproduct_Clicked"
Text="load product" />
</StackLayout>
<StackLayout
x:Name="LoadingOverlay"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="White"
HorizontalOptions="FillAndExpand"
IsVisible="{Binding loading}"
Opacity="0.5"
VerticalOptions="FillAndExpand">
<ActivityIndicator
x:Name="TaskLoader"
HorizontalOptions="CenterAndExpand"
IsRunning="{Binding running}"
IsVisible="{Binding running}"
Scale="4"
VerticalOptions="CenterAndExpand"
Color="Red" />
</StackLayout>
</AbsoluteLayout>
public partial class Page5 : ContentPage, INotifyPropertyChanged
{
public ObservableCollection<product> products { get; set; }
private bool _loading;
public bool loading
{
get { return _loading; }
set
{
_loading = value;
RaisePropertyChanged("loading");
}
}
private bool _running;
public bool running
{
get { return _running; }
set
{
_running = value;
RaisePropertyChanged("running");
}
}
public Page5()
{
InitializeComponent();
products = new ObservableCollection<product>();
loading = false;
running = false;
this.BindingContext = this;
}
private void loaddata()
{
products.Add(new product() { ProductName = "product 1", ImgSource = "a5.jpg" });
products.Add(new product() { ProductName = "product 2", ImgSource = "a6.jpg" });
products.Add(new product() { ProductName = "product 3", ImgSource = "a7.jpg" });
products.Add(new product() { ProductName = "product 4", ImgSource = "a8.jpg" });
products.Add(new product() { ProductName = "product 1", ImgSource = "a5.jpg" });
products.Add(new product() { ProductName = "product 2", ImgSource = "a6.jpg" });
products.Add(new product() { ProductName = "product 3", ImgSource = "a7.jpg" });
products.Add(new product() { ProductName = "product 4", ImgSource = "a8.jpg" });
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
private async void Getproduct_Clicked(object sender, EventArgs e)
{
loading = true;
running = true;
await Task.Delay(5000);
loaddata();
loading = false;
running = false;
}
}
public class product
{
public string ProductName { get; set; }
public string ImgSource { get; set; }
}
There is screenshot:

MVVM Navigation Force Close Xamarin Forms

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.

Categories

Resources