Create a xamarin view with a complex object binding - validation

I use XamarinForms and the plugin ValidationRules.
I have an account model, a login page which is linked to the accountviewmodel. And in my loginpage I add a xamarin view FormEntry which has a bindable property Validation of type Validatable<string>.
The bindable property has some properties I want to use: Value, Error and hasError property. I put the binding in my LoginPage and then the binding is null in my FormEntry content view. If I get the value of the validation object it's null in my formentry textchanged event.
Account Model
public ValidatableObject<string> Password { get; set; }
public ValidatableObject<string> Email { get; set; }
public Account()
{
Password = new ValidatableObject<string>();
Email = new ValidatableObject<string>();
}
private void AddValidations()
{
// Email validations
Email.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = C.T("Email is required.") });
Email.Validations.Add(new EmailRule<string> { ValidationMessage = C.T("Email is not valid.") });
//Password validations
Password.Validations.Add(new IsNotNullOrEmptyRule<string> { ValidationMessage = C.T("A password is required.") });
Password.Validations.Add(new LengthMinRule<string> { ValidationMessage = C.T("A password is required."), MinLength = 6 });
}
LoginPage
<local:FormEntry Validation="{Binding AccountInfo.Email}" Grid.Row="2" />
FormEntry Xaml
<ContentView.Resources>
<converter:ErrorValidationColorConverter x:Key="errorValidationColorConverter" />
<ResourceDictionary.MergedDictionaries>
</ResourceDictionary.MergedDictionaries>
</ContentView.Resources>
<ContentView.Content>
<!--<border:SfBorder Grid.Row="2"
Style="{DynamicResource SfBorderStyle}"
BorderColor="{Binding Source={x:Reference emailEntry}, Path=IsFocused, Converter={StaticResource errorValidationColorConverter}, ConverterParameter={x:Reference emailEntry}}">-->
<inputLayout:SfTextInputLayout x:Name="Input" LeadingViewPosition="Outside" TrailingViewPosition="Outside" ContainerType="None">
<Entry TextChanged="Entry_TextChanged" x:Name="entry"
Placeholder="Email">
</Entry>
<inputLayout:SfTextInputLayout.LeadingView>
<Label
Text="" FontFamily="{StaticResource FontAwesomeSolid}">
</Label>
</inputLayout:SfTextInputLayout.LeadingView>
<inputLayout:SfTextInputLayout.TrailingView>
<Label
x:Name="LabelError"
Text=""
FontFamily="{StaticResource FontAwesomeSolid}"
TextColor="{DynamicResource ErrorColor}"
FontSize="22">
</Label>
</inputLayout:SfTextInputLayout.TrailingView>
</inputLayout:SfTextInputLayout>
<!--</border:SfBorder>-->
</ContentView.Content>
My FormEntry cs
public FormEntry()
{
InitializeComponent();
}
public ICommand ValidateUserNameCommand => new Command(() =>
ValidateField());
private bool ValidateField()
{
return Validation.Validate();
}
public static readonly BindableProperty ValidationProperty =
BindableProperty.Create(
propertyName: "Validation",
returnType: typeof(ValidatableObject<string>),
declaringType: typeof(FormEntry),
defaultValue: default(ValidatableObject<string>));
public ValidatableObject Validation
{
get
{
return (ValidatableObject)GetValue(ValidationProperty);
}
set
{
SetValue(ValidationProperty, value);
}
}
protected override void OnPropertyChanged(string propertyName = null)
{
base.OnPropertyChanged(propertyName);
if (propertyName == ValidationProperty.PropertyName)
{
Input.ErrorText = Validation.Error;
Input.HasError = Validation.Validate();
entry.Text = Validation.Value;
LabelError.IsVisible = Input.HasError;
}
}
private void Entry_TextChanged(object sender, TextChangedEventArgs e)
{
ValidateField();
}
}

Related

Xamarin Forms CollectionView is empty

I have a Xamarin Forms CollectionView, contained within a RefreshView. The binding source is populated but its not showing anything in the CollectionView. I know the binding source is populated as I show a count in the toolbar. Can anyone spot why the list is empty?
Here is my Content Page with my RefreshView and CollectionView:
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add" Command="{Binding AddDogCommand}" />
<ToolbarItem Text="{Binding Dogs.Count}"></ToolbarItem>
</ContentPage.ToolbarItems>
<RefreshView x:DataType="local:MyDogsViewModel" Command="{Binding LoadDogsCommand}" IsRefreshing="{Binding IsBusy, Mode=TwoWay}">
<CollectionView ItemsLayout="HorizontalList" ItemsSource="{Binding Dogs}">
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid WidthRequest="100">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Label Grid.Column="1"
Text="{Binding DogName}"
FontAttributes="Bold" TextColor="Red"/>
<Label Grid.Row="1"
Grid.Column="1"
Text="{Binding Nickname}"
FontAttributes="Italic" TextColor="Green"
VerticalOptions="End" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</RefreshView>
Here is my ViewModel
public class MyDogsViewModel : BaseViewModel
{
private DogModel _selectedItem;
private DogService dogService = new DogService();
private string _dogName;
private string _nickname;
public ObservableCollection<DogModel> Dogs { get; }
public Command LoadDogsCommand { get; }
public Command<DogModel> ItemTapped { get; }
public Command AddDogCommand { get; }
public Command SaveDogCommand { get; }
public string DogName
{
get => _dogName;
set => SetProperty(ref _dogName, value);
}
public string Nickname
{
get => _nickname;
set => SetProperty(ref _nickname, value);
}
public MyDogsViewModel()
{
Title = "My Dogs";
Dogs = new ObservableCollection<DogModel>();
LoadDogsCommand = new Command(async () => await ExecuteLoadDogsCommand());
ItemTapped = new Command<DogModel>(OnItemSelected);
AddDogCommand = new Command(OnAddDog);
SaveDogCommand = new Command(OnSaveDog);
}
async Task ExecuteLoadDogsCommand()
{
IsBusy = true;
try
{
Dogs.Clear();
var dogs = await dogService.GetDogsAsync();
foreach (var d in dogs)
{
Dogs.Add(d);
}
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex);
}
finally
{
IsBusy = false;
}
}
public void OnAppearing()
{
IsBusy = true;
}
private async void OnAddDog(object obj)
{
await Shell.Current.GoToAsync(nameof(AddDogPage));
}
private async void OnSaveDog(object obj)
{
AddDogModel model = new AddDogModel
{
DogName = DogName,
Nickname = Nickname
};
await dogService.AddDog(model);
await Shell.Current.GoToAsync("..");
}
async void OnItemSelected(DogModel dog)
{
if (dog == null)
return;
}
}
DogModel class
public class DogModel
{
public int Id { get; set; }
public string DogName { get; set; }
public string Nickname { get; set; }
}
keep your xaml the same and i will edit your ViewModel and take out the properties that is causing you the issue ;
public class MyDogsViewModel : BaseViewModel
{
private DogModel _selectedItem;
private DogService dogService = new DogService();
private string _dogName;
private string _nickname;
private ObservableCollection<DogModel> dogs;
public ObservableCollection<DogModel> Dogs
{
get{return dogs;}
set{dogs=value;}
}
public Command LoadDogsCommand { get; set; }
public Command<DogModel> ItemTapped { get; set;}
public Command AddDogCommand { get; set;}
public Command SaveDogCommand { get; set;}
public MyDogsViewModel()
{
Title = "My Dogs";
Dogs = new ObservableCollection<DogModel>();
LoadDogsCommand = new Command(async () => await ExecuteLoadDogsCommand());
ItemTapped = new Command<DogModel>(OnItemSelected);
AddDogCommand = new Command(OnAddDog);
SaveDogCommand = new Command<object>(OnSaveDog);
}
async Task ExecuteLoadDogsCommand()
{
IsBusy = true;
try
{
Dogs.Clear();
var dogs = await dogService.GetDogsAsync();
foreach (var d in dogs)
{
Dogs.Add(d);
}
}
catch (Exception ex)
{
Debug.WriteLine("Exception: " + ex);
}
finally
{
IsBusy = false;
}
}
public void OnAppearing()
{
IsBusy = true;
}
private async void OnAddDog(object obj)
{
await Shell.Current.GoToAsync(nameof(AddDogPage));
}
private async void OnSaveDog(object obj)
{
DogModel newdog = obj as DogModel;
await dogService.AddDog(newdog);
await Shell.Current.GoToAsync("..");
}
async void OnItemSelected(DogModel dog)
{
if (dog == null)
return;
}
}
dont forget to bind to the viewmodel. in the xaml.cs add this in the constuctor.
this.BindingContext = new MyDogsViewModel();

How to mark the checkbox in repeater in Xamarin.Forms?

I am using checkbox control under repeater to do a radio button functionality, everything seems to be fine but now stuck on how to bind the checkbox when the page loads. I have saved the radio button text whichever was selected and once user come back to page again I want to bin what he has selected last time. Not getting any hint here how to proceed.
<grial:Repeater
x:Name="PP"
SelectionMode="Single"
InitialSelection="Empty"
ItemSize="100"
HorizontalOptions="Start"
ItemsSource="{Binding BlowerPostions}">
<grial:Repeater.ItemTemplate>
<DataTemplate>
<grial:Checkbox
IsChecked="false"
UncheckedBorderColor="Black">
<Label
TextColor="Black"
Text="{ Binding . }"
Margin="8,0" />
</grial:Checkbox>
</DataTemplate>
</grial:Repeater.ItemTemplate>
<grial:Repeater.SelectedItemTemplate>
<DataTemplate>
<grial:Checkbox
IsChecked="true"
UncheckedBorderColor="Black"
InputTransparent="true">
<Label
TextColor="Black"
Text="{ Binding . }"
Margin="8,0" />
</grial:Checkbox>
</DataTemplate>
</grial:Repeater.SelectedItemTemplate>
</grial:Repeater>
View Model :
public class ProductionViewModel : INotifyPropertyChanged
{
public ObservableCollection<BlowerPostion> _blowerPostions;
public ObservableCollection<BlowerPostion> BlowerPostions
{
get => _blowerPostions;
set
{
_blowerPostions = value;
if (PropertyChanged != null)
{
PropertyChanged(this, new
PropertyChangedEventArgs("BlowerPostions"));
}
}
}
public void LoadData()
{
BlowerPostions = new ObservableCollection<BlowerPostion>();
BlowerPostions.Add(new BlowerPostion("Left", 1));
BlowerPostions.Add(new BlowerPostion("Standard", 1));
}
}
public class BlowerPostion
{
public string Text { get; set; }
public int Id { get; set; }
public BlowerPostion(string _text, int _id)
{
Text = _text;
Id = _id;
}
}
I don't use grial:Repeater,but you can refer to the following code which use CheckBox in ListView item.
Item.cs
public class Item
{
public string Name { get; set; }
public string Type { get; set; }
public string Image { get; set; }
//This field indicates whether or not it is selected
public bool isChecked { get; set; }
}
MyViewModel.cs
public class MyViewModel
{
public ObservableCollection<Item> items { get; private set; }
public MyViewModel() {
items = new ObservableCollection<Item>();
items.Add(new Item { Name = "Tomato", Type = "Fruit", Image = "tomato.png", isChecked = true });
items.Add(new Item { Name = "Romaine Lettuce", Type = "Vegetable", Image = "lettuce.png", isChecked = false });
items.Add(new Item { Name = "Zucchini", Type = "Vegetable", Image = "zucchini.png", isChecked = false });
}
}
TestPage1.xaml
<ContentPage.Content>
<ListView x:Name="listview" ItemsSource="{Binding items}" VerticalOptions="FillAndExpand">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Orientation="Horizontal" Padding="5,0,5,0">
<Label Text="{Binding Name}" HorizontalOptions="StartAndExpand" FontSize="30"/>
<input:CheckBox IsChecked="{Binding isChecked}" Type="Check" Color="White" BoxBackgroundColor="Green" TextColor="White" HeightRequest="40"
CheckChanged="CheckBox_CheckChanged" BindingContext="{Binding .}" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage.Content>
TestPage1.xaml.cs
public partial class TestPage1 : ContentPage
{
public List<Item> selectedItems; // define `selectedItems` as the list of selected items.
public MyViewModel viewModel;
public TestPage1 ()
{
InitializeComponent ();
selectedItems = new List<Item>(); // init the `selectedItems`
viewModel = new MyViewModel();
BindingContext = viewModel;
}
private void CheckBox_CheckChanged(object sender, EventArgs e)
{
var checkbox = (Plugin.InputKit.Shared.Controls.CheckBox)sender;
var ob = checkbox.BindingContext as Item;
if (ob != null)
{
System.Diagnostics.Debug.WriteLine("isChecked = " + ob.isChecked + "<---> Name = " + ob.Name +"<---> Type = " + ob.Type );
if (ob.isChecked)
{
selectedItems.Add(ob);
}
else {
// remove the item
}
}
}
}
Note:
1.add new field isChecked in item model
public bool isChecked { get; set; }
2.Add event CheckChanged for the item.And when we check the CheckBox,we can get the corresponding value isChecked of the CheckBox.
<input:CheckBox IsChecked="{Binding isChecked}" Type="Check" Color="White" BoxBackgroundColor="Green" TextColor="White" HeightRequest="40"
CheckChanged="CheckBox_CheckChanged" BindingContext="{Binding .}" />

Xamarin CollectionView Observable Collection not updating with Searchbar

My Accounts CollectionView is not updating with the Searchbar. Xaml below.
<?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:viewmodels="clr-namespace:Pricing051721.ViewModels"
x:Class="Pricing051721.MainPage" Title="KR Pricing"
x:Name="This">
<ContentPage.BindingContext>
<viewmodels:MainPageViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Button Text="Logout" Command="{Binding LogoutCommand}" Margin="0,5,0,5"/>
<SearchBar x:Name="searchBar"
SearchCommand="{Binding PerformSearch}"
SearchCommandParameter="{Binding Text, Source={x:Reference searchBar}}"/>
<CollectionView ItemsSource="{Binding Accounts}" Margin="5">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5" >
<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.AccountSelected, Source={x:Reference This}}" CommandParameter="{Binding .}"/>
</StackLayout.GestureRecognizers>
<StackLayout >
<Label FontSize="Medium" Text="{Binding Name}" ></Label>
<Label Text="{Binding Address}"></Label>
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
</ContentPage>
I am trying to search through the Accounts already queried in the view model so I don't have to hit the database again. The search works, but Accounts is not updated.
namespace Pricing051721.ViewModels
{
public class MainPageViewModel : INotifyPropertyChanged
{
public ObservableCollection<Account> Accounts { get; set; }
public INavigation Navigation { get; set; }
public ICommand LogoutCommand { get; set; }
AdAuthenticationService authService;
public ObservableCollection<Account> baseAccountList;
public MainPageViewModel()
{
Accounts = new ObservableCollection<Account> { new Account { AllowUpdate = true, Address = "Wait", Name = "Loading" } };
authService = new AdAuthenticationService();
Task.Run(async () =>
{
if (!authService.IsAuthenticated)
{
var response = authService.Authenticate();
await Update(response.AccessToken, "");
}
else await Update(authService.AccessToken, "");
});
AccountSelected = new Command<Account>(async (a) =>
{
if (!a.AllowUpdate)
return;
await Navigation.PushAsync(new UpdateAccountView(a));
return;
var result = await UserDialogs.Instance.PromptAsync(new PromptConfig
{
InputType = InputType.Name,
OkText = "Change",
Title = "Enter New Column Break",
Text = a.ColumnBreak
});
if (result.Ok && result.Text != null && !result.Text.Trim().Equals(""))
{
a.ColumnBreak = result.Text;
isUpdating = true;
var ok = await crm.Update(a);
var message = ok ? "Account Updated!" : "Unable to update!";
await UserDialogs.Instance.AlertAsync(new AlertConfig
{
Title = "Message",
Message = message,
OkText = "Ok"
});
isUpdating = false;
}
}, _ => !isUpdating);
LogoutCommand = new Command(new Action(() => {
authService.Logout();
Environment.Exit(Environment.ExitCode);
}));
}
//search
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand PerformSearch => new Command<string>((string query) =>
{
Accounts = SearchAccounts(query);
});
private bool isUpdating = false;
private Crm crm;
public ObservableCollection<Account> accounts;
public async Task Update(string accessToken, string query)
{
Crm.Setup(accessToken);
crm = Crm.AuthenticatedCrmService;
var accounts = await crm.GetAccounts();
Accounts.RemoveAt(0);
accounts.ForEach(a => Accounts.Add(a));
}
public ObservableCollection<Account> SearchAccounts(string query)
{
Task.Run(async () =>
{
if (!authService.IsAuthenticated)
{
var response = authService.Authenticate();
await Update(response.AccessToken, "");
}
else await Update(authService.AccessToken, "");
});
baseAccountList = Accounts;
if (!(query == ""))
{
var normalizedQuery = query?.ToLower() ?? "";
List<Account> accountsList = (List<Account>)Accounts.Where(f => f.Name.ToLowerInvariant().Contains(normalizedQuery)).ToList();
ObservableCollection<Account> accounts = new ObservableCollection<Account>(accountsList);
Accounts.Clear();
return accounts;
}
else
{
accounts = Accounts;
return accounts;
}
}
public ICommand AccountSelected { get; set; }
}
}
I don't need a neat solution (as you can tell by my code so far), just something that will work Thanks in advance!
My Accounts CollectionView is not updating with the Searchbar
From your code, you don't post some code about PerformSearch command, I don't know how do you search data by searchbar. I do one sample about search some data by searchbar, display in collectionview, you can modify your code according to the following code.
<SearchBar
x:Name="searchBar"
SearchCommand="{Binding PerformSearch}"
SearchCommandParameter="{Binding Text, Source={x:Reference searchBar}}" />
<CollectionView Margin="5" ItemsSource="{Binding Accounts}">
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Margin="5">
<!--<StackLayout.GestureRecognizers>
<TapGestureRecognizer Command="{Binding BindingContext.AccountSelected, Source={x:Reference This}}" CommandParameter="{Binding .}" />
</StackLayout.GestureRecognizers>-->
<StackLayout>
<Label FontSize="Medium" Text="{Binding Name}" />
<Label Text="{Binding Address}" />
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
public partial class Page15 : ContentPage
{
public Page15()
{
InitializeComponent();
this.BindingContext = new AccountViewModel();
}
}
public class AccountViewModel
{
public ObservableCollection<Account> AccountList { get; set; }
public ObservableCollection<Account> Accounts { get; set; }
public ICommand PerformSearch { get; set; }
public AccountViewModel()
{
AccountList = new ObservableCollection<Account>();
Accounts = new ObservableCollection<Account>();
for(int i=0;i<30;i++)
{
Account a = new Account();
a.Name = "account" + i;
a.Address = "address " + i;
AccountList.Add(a);
Accounts.Add(a);
}
PerformSearch = new Command(search => {
if(search!=null)
{
string searchtext = (string)search;
if (!string.IsNullOrEmpty(searchtext))
{
Accounts.Clear();
List<Account> list= AccountList.Where((account) => account.Name.ToLower().Contains(searchtext) || account.Address.ToLower().Contains(searchtext)).ToList();
foreach(Account a in list)
{
Accounts.Add(a);
}
}
Accounts = AccountList;
}
else
{
Accounts = AccountList;
}
});
}
}
public class Account
{
public string Name { get; set; }
public string Address { get; set; }
}

Login MVVM / Labels

i have a question regarding to Binding. I have a Login that I now decided to transfer to MVVM until now i had labels with content "wrong password" and such in code behind and i was setting their visibility. Btw I do have RESX file and I am binding my labels, just not sure how to approach this.
bool isPreparedToBeSubmitted = true;
if (string.IsNullOrEmpty(UserName))
{
isPreparedToBeSubmitted = false;
emailValLabel.IsVisible = true;
}
if (string.IsNullOrEmpty(Password))
{
isPreparedToBeSubmitted = false;
passwordEntryValLabel.IsVisible = true;
}
But I think this can be done much nicer, but I am not sure how. Do i get the visibility bool in Model and then set binding to the label in View?
Since you want to use MVVM. It would be better to bind the text of entry to ViewModel . Don't forget to set the binding mode as OneWayToSource .
You could check the following demo . The page contains two entries . The submit button will appear when user both input the user name and password .
in xaml
<StackLayout VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand">
<Entry Placeholder="input username" Text="{Binding UserName,Mode=OneWayToSource}" HeightRequest="40" WidthRequest="200" />
<Entry Placeholder="input password" Text="{Binding Password,Mode=OneWayToSource}" HeightRequest="40" WidthRequest="200" />
<Button Text="Submit" IsVisible="{Binding IsVisible}" Command="{Binding SubmitCommand}" />
</StackLayout>
in ViewModel
public class MyViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public ICommand SubmitCommand { get; set; }
//IsVisible
bool isVisible;
public bool IsVisible
{
get
{
return isVisible;
}
set
{
if (isVisible != value)
{
isVisible = value;
NotifyPropertyChanged("IsVisible");
}
}
}
string userName;
public string UserName
{
get
{
return userName;
}
set
{
if (userName != value)
{
userName = value;
IsSubmitVisible();
NotifyPropertyChanged("UserName");
}
}
}
string password;
public string Password
{
get
{
return password;
}
set
{
if (password != value)
{
password = value;
IsSubmitVisible();
NotifyPropertyChanged("Password");
}
}
}
void IsSubmitVisible()
{
if (!string.IsNullOrEmpty(UserName) && !string.IsNullOrEmpty(Password))
{
IsVisible = true;
}
else
{
IsVisible = false;
}
}
public MyViewModel()
{
SubmitCommand = new Command(()=> {
//...
});
}
}

Bind controls with Model object in ViewModel class in Xamarin forms

I am learning MVVM in Xamarin forms using Prism. I have implemented a login functionality which uses a User model class. But the bindings are not working. Please review the code and suggest corrections.
I am not sure how to bind the control's text property to the Model class object's properties.
LoginPage.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:prism="http://prismlibrary.com"
prism:ViewModelLocator.AutowireViewModel="True"
x:Class="LeaveTracker.Views.LoginPage"
Title="{Binding Title}">
<StackLayout Orientation="Vertical" BindingContext="{Binding UserObj}">
<Entry Placeholder="User ID" Text="{Binding UserID}"/>
<Entry Placeholder="Password" Text="{Binding Password}" IsPassword="True"/>
</StackLayout>
</ContentPage>
LoginPageViewModel.cs
public class LoginPageViewModel : ViewModelBase
{
private User _user;
private IFirebaseService _firebaseService;
public User UserObj
{
get { return _user; }
set { SetProperty(ref _user, value); }
}
public DelegateCommand LoginCommand { get; set; }
public LoginPageViewModel(IFirebaseService firebaseService, INavigationService navigationService) : base(navigationService)
{
Title = "Log In";
_firebaseService = firebaseService;
LoginCommand = new DelegateCommand(Login, CanLogin);
}
private void Login()
{
var x = _firebaseService.LoginAsync(_user);
}
private bool CanLogin()
{
if (string.IsNullOrEmpty(_user.UserID) && string.IsNullOrEmpty(_user.Password))
{
return true;
}
return false;
}
User.cs
public class User
{
private string _userID;
public string UserID
{
get { return _userID; }
set { _userID = value; }
}
private string _password;
public string Password
{
get { return _password; }
set { _password = value; }
}
}
your BindingContext is LoginPageViewModel, and UserObj is a property of the VM, so your binding path needs to include UserObj
<Entry Placeholder="User ID" Text="{Binding UserObj.UserID}"/>
<Entry Placeholder="Password" Text="{Binding UserObj.Password}" IsPassword="True"/>

Resources