Accessing an element inside of a Collectionview datatemplate in Xamarin.Forms - xamarin.forms

I am fairly new to Xamarin.Forms and am attempting to access a child element of a CollectionView DataTemplate.
The DataTemplate contains a horizontal StackLayout consisting of a Checkbox and a Label.
What I would like to do is to make the Checkbox's IsChecked property equal to true whenever the CollectionView element is selected, in order to show the Checkbox as checked when an element is selected.
The highest number of elements that I will ever have in this CollectionView are 2.
Here is some code to illustrate what I am trying to do:
<?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"
x:Class="CheckBoxExample.MainPage">
<StackLayout>
<!-- Place new controls here -->
<Label
Text="Welcome to Xamarin.Forms!"
HorizontalOptions="Center"
VerticalOptions="CenterAndExpand" />
<Frame>
<CollectionView
ItemsSource="{Binding Customers}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout
Orientation="Horizontal">
<CheckBox
IsChecked="" />
<Label
Text="{Binding .}"
VerticalOptions="Center" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Frame>
</StackLayout>
</ContentPage>

In order to check a CheckBox whenever it is selected, and uncheck it when it is unselected, and assuming, as you mentioned, that you will only have two items, the following code should put you on the right track:
First, We define our model in the following way
public class Costumer : INotifyPropertyChanged
{
private String _Text;
public String Text
{
get => _Text;
set
{
if (_Text != value)
{
_Text = value;
OnPropertyChanged();
}
}
}
private Boolean _Checked;
public Boolean IsChecked
{
get => _Checked;
set
{
if (_Checked != value)
{
_Checked = value;
OnPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public class Costumers : List<Costumer>, INotifyPropertyChanged
{
private Costumer _CostumerSelected;
public Costumer CostumerSelected
{
get => _CostumerSelected;
set
{
if (_CostumerSelected != value)
{
if (_CostumerSelected!=null) _CostumerSelected.IsChecked = false;
_CostumerSelected = value;
OnPropertyChanged();
_CostumerSelected.IsChecked = true;
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In the previous code, note what is going on in the CostumerSelected setter: If the selection changed, and an item is already selected, it is unchecked. After that, the new selected item is checked.
Then in the XAML
<ContentPage.Content>
<StackLayout>
<Frame >
<CollectionView ItemsSource="{Binding .}"
SelectedItem="{Binding CostumerSelected}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Horizontal">
<CheckBox IsChecked="{Binding IsChecked}" />
<Label Text="{Binding Text}"
VerticalOptions="Center" />
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</Frame>
</StackLayout>
</ContentPage.Content>
In the code above, note that i assigned the SelectionMode property, in order to allow selection! Also, i bound the SelectedItem property to the CostumerSelected in my Costumers Model.
And in the code behind, we simply populate the CollectionView:
protected override void OnAppearing()
{
BindingContext = new Costumers() { new Costumer() { Text = "James Sku" }, new Costumer() { Text = "Daniel Gomez" } };
base.OnAppearing();
}

Related

LongPress dosent get trigered

I installed the Xamarin community toolkit, and I am trying to play a message to the user when long pressing the item, but for some reason, it doesn't trigger. I want to send the selected item as a parameter, and delete it
I added a little portion of the ViewModel, and the binding context is set in code behind
<ContentPage.Content>
<ListView x:Name="CarsList"
Grid.Row="1"
SeparatorVisibility="Default"
ItemsSource="{Binding Cars}"
HasUnevenRows="True"
SelectionMode="None"
SelectedItem="{Binding SelectedCar}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell xct:TouchEffect.Command="{Binding Source={x:Reference ListPage}, Path = BindingContext.PressedCommand}"
xct:TouchEffect.CommandParameter="{Binding .}">
<local:CarView Padding="0,10,0,0" />
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
</ContentPage>
public Command PressedCommand
{
get; set;
}
public SampleViewModel()
{
PressedCommand = new Command(PressAction);
GridSpan = Device.Idiom == TargetIdiom.Phone ? 1 : 2;
BuildCars();
}
private void PressAction(object obj) => throw new NotImplementedException();
private void LongAction(object obj)
{
Application.Current.MainPage.DisplayAlert("Warning", "do you want to delete?", "OK");
}
.....
private ObservableCollection<Car> _cars;
public ObservableCollection<Car> Cars
{
get
{
return _cars;
}
set
{
SetProperty(ref _cars, value);
}
}
}

How to make a checkbox stay checked when i navigate through pages? Xamarin

I have this listview and in the listview I have an ItemTemplate with a DataTemplate and a ViewCell in which I have a checkbox named "box1". I want to make it stay checked when i switch pages, but i can't acess it via name because it is in a DataTemplate and in a ViewCell. I have tried to name all the controls down to the checkbox and get access to it like that, but it does not seem to work...
This is my xaml:
<ListView SeparatorVisibility="None"
BackgroundColor="Transparent"
VerticalOptions="Center"
x:Name="listView"
HasUnevenRows="True"
>
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Meal"
x:Name="mydt"
>
<ViewCell
x:Name="myvc"
>
<Grid BackgroundColor="Transparent"
x:Name="mygrid"
>
<Frame BackgroundColor="Transparent"
CornerRadius="20"
x:Name="myframe"
>
<StackLayout Orientation="Horizontal"
>
<Image Source="meal.png" WidthRequest="59" Margin="0, 0, 15, 0"/>
<StackLayout Orientation="Vertical" WidthRequest="300">
<Label VerticalOptions="Start"
FontSize="20"
Text="{Binding Name}"
FontAttributes="Bold"/>
<Label VerticalOptions="Start"
FontSize="15"
Text="{Binding Ingredients}"/>
<StackLayout Orientation="Horizontal">
<Label VerticalOptions="Start"
FontSize="15"
Text="{Binding Calories}"
TextColor="OrangeRed"/>
<Label Text="kcal"
FontSize="15"
TextColor="OrangeRed"/>
</StackLayout>
</StackLayout>
<CheckBox
x:Name="box1"
IsChecked="{Binding Checked}"
Color="Green"
Margin="60, 0, 0, 0"
CheckedChanged="box1_CheckedChanged"
BindingContext="{Binding ., Mode=TwoWay}"
/>
</StackLayout>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
This is my event handler from the Content Page in cs:
private void box1_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
var meal = listView.SelectedItem as Meal;
if (listView.SelectedItem != null)
{
if (e.Value == true)
{
long cal = long.Parse(meal.Calories);
calories_consumed = calories_consumed + cal;
ch = true;
}
else
{
long cal = long.Parse(meal.Calories);
calories_consumed = calories_consumed - cal;
ch = false;
}
}
label_cal.Text = calories_consumed.ToString();
}
This is my updated Meal class using INotifyPropertyChanged:
public class Meal : INotifyPropertyChanged
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged(nameof(Name));
}
}
private string ingredients;
public string Ingredients
{
get { return ingredients; }
set
{
ingredients = value;
OnPropertyChanged(nameof(Ingredients));
}
}
private string calories;
public string Calories
{
get { return calories; }
set
{
calories = value;
OnPropertyChanged(nameof(Calories));
}
}
private bool isChecked;
public bool IsChecked
{
get
{
return isChecked;
}
set
{
isChecked = value;
OnPropertyChanged(nameof(IsChecked));
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
And this is my code behind for the ContentPage:
protected override async void OnAppearing()
{
base.OnAppearing();
listView.ItemsSource = new ObservableCollection<Meal>(await App.Database.GetMealAsync());
}
public static bool ch;
Event handler for the checkbox in the code behind:
private void box1_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
var meal = listView.SelectedItem as Meal;
if (listView.SelectedItem != null)
{
if (e.Value == true)
{
long cal = long.Parse(meal.Calories);
calories_consumed = calories_consumed + cal;
ch = true;
}
else
{
long cal = long.Parse(meal.Calories);
calories_consumed = calories_consumed - cal;
ch = false;
}
}
meal.IsChecked = ch;
label_cal.Text = calories_consumed.ToString();
}
To be short you can just save the value in Preferences or make a variable in a model that is static and bind that values OnAppearing
There are mainly two ways that you could store the checkbox's state.
1.You could use Json to Serialize and deserialize the model that has a IsChecked property that binding with the checkbox.For more details, you could refer to this thread.
Code in checkbox_CheckedChanged event:
private void checkbox_CheckedChanged(object sender, CheckedChangedEventArgs e)
{
var checkbox = (CheckBox)sender;
var selectMeal = checkbox.BindingContext as Meal;
selectMeal.Checked = e.Value;
//save the data and checkbox state,you could save the data as a json string
string json = JsonConvert.SerializeObject(blistView);
Preferences.Set("listmeals", json);
}
2.You could store the state of the checkbox using sqlite-net-pcl.Please refer to below MS official docs for more details.
And then retrieve the check state of the checkbox via OnAppearing Method.
protected override void OnAppearing()
{
// retrieve the check state of the checkbox in your sqlite database.
base.OnAppearing();
TodoItemDatabase database = await TodoItemDatabase.Instance;
listView.ItemsSource = await database.GetItemsAsync();
}
MS official docs:https://learn.microsoft.com/en-us/xamarin/xamarin-forms/data-cloud/data/databases
The way you are connecting your class your view/xaml is incorrect. If you want to do it without MVVM you can go about it by creating a model that implements INotifyPropertyChanged and an ObservableCollection as listView itemssource.
Model class Meal could look like this:
public class Meal : INotifyPropertyChanged
{
private string name;
public string Name
{
get { return name; }
set
{
name = value;
OnPropertyChanged(nameof(Name));
}
}
private string ingredients;
public string Ingredients
{
get { return ingredients; }
set
{
ingredients = value;
OnPropertyChanged(nameof(Ingredients));
}
}
private string calories;
public string Calories
{
get { return calories; }
set
{
calories = value;
OnPropertyChanged(nameof(Calories));
}
}
private bool isChecked;
public bool IsChecked
{
get { return isChecked; }
set
{
isChecked = value;
OnPropertyChanged(nameof(IsChecked));
}
}
#region INotify property changed
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
if (handler != null)
handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
The MainPage.xaml like this:
<StackLayout>
<ListView SeparatorVisibility="None"
BackgroundColor="Transparent"
VerticalOptions="Center"
x:Name="listView"
HasUnevenRows="True">
<ListView.ItemTemplate>
<DataTemplate x:DataType="model:Meal" x:Name="mydt" >
<ViewCell x:Name="myvc" >
<Grid BackgroundColor="Transparent"
x:Name="mygrid" >
<Frame BackgroundColor="Transparent"
CornerRadius="20"
x:Name="myframe">
<StackLayout Orientation="Horizontal">
<Image Source="meal.png" WidthRequest="59" Margin="0, 0, 15, 0"/>
<StackLayout Orientation="Vertical" WidthRequest="300">
<Label VerticalOptions="Start"
FontSize="20"
Text="{Binding Name}"
FontAttributes="Bold"/>
<Label VerticalOptions="Start"
FontSize="15"
Text="{Binding Ingredients}"/>
<StackLayout Orientation="Horizontal">
<Label VerticalOptions="Start"
FontSize="15"
Text="{Binding Calories}"
TextColor="OrangeRed"/>
<Label Text="kcal" FontSize="15" TextColor="OrangeRed"/>
</StackLayout>
</StackLayout>
<CheckBox x:Name="box1" IsChecked="{Binding IsChecked}" Color="Green" Margin="60, 0, 0, 0" />
</StackLayout>
</Frame>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<Button Clicked="Button_Clicked" Text="Check status items"/>
</StackLayout>
And your MainPage.xaml.cs code behind like this:
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
listView.ItemsSource = new ObservableCollection<Meal>(new List<Meal>
{
new Meal { Name = "Meal 01", Ingredients = "Ingredients 01", Calories = "250" },
new Meal { Name = "Meal 02", Ingredients = "Ingredients 02", Calories = "350" },
new Meal { Name = "Meal 03", Ingredients = "Ingredients 03", Calories = "450" }
});
}
/// <summary>
/// check items ischecked status
/// </summary>
private void Button_Clicked(object sender, EventArgs e)
{
foreach (var item in listView.ItemsSource)
{
if (item is Meal meal && meal.IsChecked)
System.Diagnostics.Debug.WriteLine($"{meal.Name} is checked");
}
}
}
Look at the other answer for saving the model and/or list. When saved the list can be retrieved in the OnAppearing and set instead of recreated as shown in this example. I've added a button on the bottom that prints out which Meals are selected in the output window. See screenshot:

Binding StackLayout to ViewModel doens't work

I would like to have a property in my ViewModel that is linked to my StackLayout. I tried this by Binding my StackLyout to the ViewModel.
When I click on a button, this layout should be made invisible.
When I do this with the code below, my program crashes with a NulReferenceObject: Object Reference not set to an instance of an object. The StackLayout that i am talking about is the first one in the code below.
<FlexLayout>
<StackLayout BindableLayout.ItemTemplate="{Binding CreateQuizPageQuizNameSL}"> // This StackLayout should be bind to the ViewModel
<Label Text="Create New Quiz" />
<StackLayout >
<Entry Text="{Binding QuizNameInput}" Placeholder="Enter quiz name"/>
</StackLayout>
</StackLayout>
<Button Command="{Binding SubmitCreateQuizCommand}" Text="Create my quiz now!"></Button>
</FlexLayout>
ViewModel
internal class CreateQuizPageViewModel
{
// Quiz Name Input
public String QuizNameInput { get; set; }
// Command submit creating a quiz
public Command SubmitCreateQuizCommand { get; set; }
public StackLayout CreateQuizPageQuizNameSL { get; set; } = new StackLayout();
public CreateQuizPageViewModel()
{
// Declaring a new command, giving the OnSubmitCreateNewQuizClick to the delegate
SubmitCreateQuizCommand = new Command(OnSubmitCreateNewQuizClick);
}
// When a user submit the creation of new quiz
public void OnSubmitCreateNewQuizClick()
{
CreateQuizPageQuizNameSL.IsVisible = false;
}
}
Here is how to switch two layouts using IsVisible binding.
FIRST Add Nuget Xamarin.CommunityToolkit to your Xamarin Forms project. (The one that is "MyProjectName", without ".iOS" or ".Android" at end.)
TwoLayoutPage.xaml:
<?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:xct="http://xamarin.com/schemas/2020/toolkit"
xmlns:local="clr-namespace:TestBugs"
x:Class="TestBugs.TwoLayoutPage">
<ContentPage.BindingContext>
<local:TwoLayoutViewModel/>
</ContentPage.BindingContext>
<ContentPage.Resources>
<ResourceDictionary>
<xct:InvertedBoolConverter x:Key="InvertedBoolConverter" />
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<StackLayout>
<StackLayout
IsVisible="{Binding UseSecondLayout, Converter={StaticResource InvertedBoolConverter}}"
VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Label Text="First Layout" FontSize="20" />
<Button Text="To Second" Command="{Binding SwitchToSecondLayoutCommand}" />
</StackLayout>
<StackLayout IsVisible="{Binding UseSecondLayout}"
VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Label Text="Second Layout!" FontSize="32" />
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
TwoLayoutViewModel.cs:
using Xamarin.Forms;
namespace TestBugs
{
public class TwoLayoutViewModel : BindableObject
{
private bool _usesecondLayout = false;
public bool UseSecondLayout {
get => _usesecondLayout;
set {
_usesecondLayout = value;
OnPropertyChanged();
}
}
public TwoLayoutViewModel()
{
SwitchToSecondLayoutCommand = new Command(SwitchToSecondLayout);
}
public Command SwitchToSecondLayoutCommand { get; set; }
private void SwitchToSecondLayout()
{
UseSecondLayout = true;
}
}
}

How to change image source when a property changes through databinding in XAML from viewmodel in xamarin forms?

I am working on providing wishlist feature for my app by tapping wishlist icon on each product in list through MVVM. Once tapped, an API call is made to update database(add/remove from wishlist table). Based on result from api call, I updated the specific product's respective property to either 'True' or 'False'. Once property updated, I want to change the icon image source of corresponding product. I am using trigger on wishlist icon to differentiate non-wishlist and wiahlist products while binding the list itself.
My code is below,
MODEL
public class PublisherProducts
{
public long ProductId { get; set; }
public string ProductName { get; set; }
public string ImageURL { get; set; }
public decimal Price { get; set; }
public bool IsWishlistProduct { get; set; }
}
VIEWMODEL
public class OnlineStoreViewModel : BaseViewModel
{
private ObservableCollection<PublisherProducts> publisherProducts;
public Command<long> WishlistTapCommand { get; }
public OnlineStoreViewModel()
{
publisherProducts = new ObservableCollection<PublisherProducts>();
WishlistTapCommand = new Command<long>(OnWishlistSelected);
}
public ObservableCollection<PublisherProducts> PublisherProducts
{
get { return publisherProducts; }
set
{
publisherProducts = value;
OnPropertyChanged();
}
}
public async Task GetProducts(long selectedCategoryId)
{
try
{
...
PublisherProducts = new ObservableCollection<PublisherProducts>(apiresponse.ProductList);
...
}
catch (Exception ex) { ... }
finally { ... }
}
async void OnWishlistSelected(long tappedProductId)
{
if (tappedProductId <= 0)
return;
else
await UpdateWishlist(tappedProductId);
}
public async Task UpdateWishlist(long productId)
{
try
{
var wishlistResponse = // api call
var item = PublisherProducts.Where(p => p.ProductId == productId).FirstOrDefault();
item.IsWishlistProduct = !item.IsWishlistProduct;
PublisherProducts = publisherProducts; *Stuck here to toggle wishlist icon*
await App.Current.MainPage.DisplayAlert("", wishlistResponse.Message, "Ok");
}
catch (Exception ex) { ... }
finally { ... }
}
}
XAML
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" ... >
<ContentPage.Content>
<ScrollView>
<StackLayout Padding="15,0,15,10">
<FlexLayout x:Name="flxLayout" BindableLayout.ItemsSource="{Binding PublisherProducts}" ...>
<BindableLayout.ItemTemplate>
<DataTemplate>
<AbsoluteLayout Margin="6" WidthRequest="150">
<Frame Padding="0" WidthRequest="150" CornerRadius="10" HasShadow="True">
<StackLayout Orientation="Vertical" Padding="10" HorizontalOptions="FillAndExpand">
<Image Source="{Binding ImageURL}" WidthRequest="130" HeightRequest="130" HorizontalOptions="Center"/>
<Label Text="{Binding ProductName}" Style="{StaticResource ProductNameStyle}"></Label>
...
<StackLayout ...>
...
<Frame x:Name="wlistFrame" Padding="0" WidthRequest="30" HeightRequest="30" CornerRadius="10" BorderColor="#02457A">
<StackLayout Orientation="Horizontal" VerticalOptions="Center" HorizontalOptions="Center">
<Image x:Name="wlImage" WidthRequest="13" HeightRequest="12" HorizontalOptions="Center" VerticalOptions="Center" Source="ic_wishlist_open">
<Image.Triggers>
<DataTrigger TargetType="Image" Binding="{Binding IsWishlistProduct}" Value="true">
<Setter Property="Source" Value="ic_wishlist_close" />
</DataTrigger>
</Image.Triggers>
</Image>
</StackLayout>
<Frame.GestureRecognizers>
<TapGestureRecognizer Command="{Binding Source={RelativeSource AncestorType={x:Type local:OnlineStoreViewModel}}, Path=WishlistTapCommand}" CommandParameter="{Binding ProductId}" NumberOfTapsRequired="1" />
</Frame.GestureRecognizers>
</Frame>
</StackLayout>
</StackLayout>
</Frame>
</AbsoluteLayout>
</DataTemplate>
</BindableLayout.ItemTemplate>
</FlexLayout>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
I am stuck at this place to change wishlist icon, when 'IsWishlistProduct' property value is changed in UpdateWishlist().
Guessing through your code, the BaseViewModel contains code similar to the following:
public class BaseViewModel : INotifyPropertyChanged
{
...
public event PropertyChangedEventHandler PropertyChanged;
...
public void OnPropertyChanged(string name)
{
this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
...
}
And your viewmodel should be like this:
...
public ObservableCollection<PublisherProducts> PublisherProducts
{
get { return publisherProducts; }
set
{
publisherProducts = value;
OnPropertyChanged(nameof(PublisherProducts));
}
}
...
As Jason mentioned, If there is a change in data in the ViewModel, it is reflected in the UI when it is notified to the View through NotifyPropertyChanged. You already implemented "OnPropertyChanged" function in your BaseViewModel but it seems you don't pass the object name.

How to use mvvm to create login page in xamarin forms

I'm trying to create login page in xamarin forms using mvvm design pattern
I got and expectation in my code but i don't know the reason
I Created ViewModel page it's code
public class LoginViewModel:ContentPage,INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public User user { get; set; }
private string username;
public string Username
{
get { return username; }
set
{
username = value;
PropertyChanged(this, new PropertyChangedEventArgs("Username"));
}
}
private string password;
public string Password
{
get { return password; }
set { password = value;
PropertyChanged(this, new PropertyChangedEventArgs("Password"));
}
}
public ICommand SubmitCommand { set; get; }
public LoginViewModel()
{
user = new User();
SubmitCommand = new Command(OnSubmit);
}
private async Task<bool> CheckLogin()
{
user = await Services.LoginService.GetUserByUsername(username);
if (user != null)
{
if (user.Password.Trim().Equals(password))
{
return true;
}
else
{
await LoginView.loginView.DisplayAlert("Error", "Invalid Login, try again", "OK");
return false;
}
}
return false;
}
private async void OnSubmit()
{
await CheckLogin();
}
}
}
and MyLoginView.xaml
<ContentPage
xmlns:vm="clr-namespace:PickNgo.ViewModel"
x:Class="PickNgo.View.LoginView"
BackgroundColor="White">
<ContentPage.Content>
<StackLayout>
<StackLayout BackgroundColor="#F27D0C">
<Image HorizontalOptions="Center" WidthRequest="300" Source="logo.png"/>
</StackLayout>
<StackLayout Padding="100,10,100,0">
<Frame CornerRadius="10" BackgroundColor="White" Padding="0" Margin="0">
<Entry x:Name="Email" Text="{Binding Username}" Placeholder="Enter your username"
PlaceholderColor="Black"
Keyboard="Email"
TextColor="Black"/>
</Frame>
<BoxView HeightRequest="10"/>
<Frame CornerRadius="10" BackgroundColor="White" Padding="0" Margin="0">
<Entry x:Name="Password" Text="{Binding Password}" Placeholder="Enter your password"
PlaceholderColor="Black" HeightRequest="40" WidthRequest="40"
IsPassword="True"
TextColor="Black"/>
</Frame>
</StackLayout>
<StackLayout Padding="100,30,100,0">
<Frame CornerRadius="20" BackgroundColor="#FF6600" Padding="0" Margin="0">
<Button Command="{Binding SubmitCommand}" Text="Login" Margin="0" TextColor="White" BackgroundColor="#FF6600"
FontAttributes="Bold" FontSize="Large"/>
</Frame>
</StackLayout>
</StackLayout>
</ContentPage.Content>
</ContentPage>
and my login.cs
public partial class LoginView : ContentPage
{
public Action DisplayInvalidLoginPrompt;
public static LoginView loginView;
public LoginView ()
{
InitializeComponent();
}
}
It throw objectSystem.NullReferenceException: Object reference not set to an instance of an object.
in this line
await LoginView.loginView.Navigation.PushModalAsync(new WelcomeView());
when i debug i found loginview is set to null but i don't know why ... any help ?
Its because you haven't initialized LoginView's loginView variable.
To be honest, you really don't need the public static LoginView loginView variable (the class itself is already of type LoginView). If you want to display an alert, simply use PickNgo.App.Current.MainPage.DisplayAlert("", "", "OK"); (assuming PickNgo is the name of your project)

Resources