How to share View Model between pages? - xamarin

I can add data to the viewmodel, but when I try to access the same viewmodel from another page, the data is lost. How can I use the same viewmodel across multiple pages?
ViewModel Code
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using System.Windows.Input;
using Xamarin.Forms;
namespace App1
{
class DebtViewModel
{
ObservableCollection<Debt> _Debt = new ObservableCollection<Debt>();
public System.Windows.Input.ICommand AddAccountCommand => new Command(AddAccount);
public System.Windows.Input.ICommand RemoveAccountCommand => new Command(RemoveAccount);
public System.Windows.Input.ICommand UpdateAccountCommand => new Command(UpdateAccount);
public ObservableCollection<Debt> Debt { get; set; }
public string Account { get; set; }
public string SelectedAccount { get; set; }
public double AnnualPercentageRate { get; set; }
public decimal Amount { get; set; }
public decimal MonthlyPayment { get; set; }
public bool IntroductoryRate { get; set; }
public double IntroductoryPercentageRate { get; set; }
public int IntroductoryRange { get; set; }
public DebtViewModel()
{
ObservableCollection<Debt> Debts = _Debt;
}
public void AddAccount()
{
var debt = new Debt(Account, Amount, AnnualPercentageRate, MonthlyPayment, IntroductoryRate,
IntroductoryPercentageRate, IntroductoryRange);
if (Account != null)
{
_Debt.Add(debt);
}
}
public void RemoveAccount()
{
//Debt.Remove(SelectedAccount);
}
public void UpdateAccount()
{
//int newIndex = Debt.IndexOf(SelectedAccount);
//Debt.Remove(SelectedAccount);
//Debt.Add(Account);
//int oldIndex = Debt.IndexOf(Account);
//Debt.Move(oldIndex, newIndex);
}
}
}
List Page
<?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"
xmlns:local="clr-namespace:App1"
mc:Ignorable="d"
x:Class="App1.ListViewPage">
<!-- Required to map viewmodel -->
<ContentPage.BindingContext>
<local:DebtViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add"></ToolbarItem>
</ContentPage.ToolbarItems>
<!-- Bind variable in view model to listview itemsource -->
<ContentPage.Content>
<StackLayout>
<!--<Entry Placeholder="Account"
Text="{Binding Account}"/>
<Button Text="Add" Command="{Binding AddAccountCommand}"></Button>
<Button Text="Remove" Command="{Binding RemoveAccountCommand}"></Button>
<Button Text="Update" Command="{Binding UpdateAccountCommand}"></Button>-->
<!--textcell, custom cells, or image cell-->
<ListView ItemsSource="{Binding Debt}" SelectedItem="{Binding SelectedAccount}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding AccountName}"
FontSize="Medium"
VerticalTextAlignment="Start"
Grid.Column="0"></Label>
<Label Text="Balance"
VerticalTextAlignment="Start"
Grid.Column="1"></Label>
<Label Text="{Binding InitialAmount}"
VerticalTextAlignment="End"
Grid.Column="1"></Label>
<Label Text="APR"
VerticalTextAlignment="Start"
Grid.Column="2"></Label>
<Label Text="{Binding AnnualPercentageRate}"
VerticalTextAlignment="End"
Grid.Column="2"></Label>
<Label Text="Monthly Payment"
VerticalTextAlignment="Start"
Grid.Column="3"></Label>
<Label Text="{Binding MonthlyPayment}"
VerticalTextAlignment="End"
Grid.Column="3"></Label>
<Image Source="edit.png" Grid.Column="4"></Image>
<Image Source="trash.jpg" Grid.Column="5"></Image>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>
Add Page
<?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"
xmlns:local="clr-namespace:App1"
mc:Ignorable="d"
x:Class="App1.ListViewPage">
<!-- Required to map viewmodel -->
<ContentPage.BindingContext>
<local:DebtViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add"></ToolbarItem>
</ContentPage.ToolbarItems>
<!-- Bind variable in view model to listview itemsource -->
<ContentPage.Content>
<StackLayout>
<!--<Entry Placeholder="Account"
Text="{Binding Account}"/>
<Button Text="Add" Command="{Binding AddAccountCommand}"></Button>
<Button Text="Remove" Command="{Binding RemoveAccountCommand}"></Button>
<Button Text="Update" Command="{Binding UpdateAccountCommand}"></Button>-->
<!--textcell, custom cells, or image cell-->
<ListView ItemsSource="{Binding Debt}" SelectedItem="{Binding SelectedAccount}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="3*" />
</Grid.ColumnDefinitions>
<Label Text="{Binding AccountName}"
FontSize="Medium"
VerticalTextAlignment="Start"
Grid.Column="0"></Label>
<Label Text="Balance"
VerticalTextAlignment="Start"
Grid.Column="1"></Label>
<Label Text="{Binding InitialAmount}"
VerticalTextAlignment="End"
Grid.Column="1"></Label>
<Label Text="APR"
VerticalTextAlignment="Start"
Grid.Column="2"></Label>
<Label Text="{Binding AnnualPercentageRate}"
VerticalTextAlignment="End"
Grid.Column="2"></Label>
<Label Text="Monthly Payment"
VerticalTextAlignment="Start"
Grid.Column="3"></Label>
<Label Text="{Binding MonthlyPayment}"
VerticalTextAlignment="End"
Grid.Column="3"></Label>
<Image Source="edit.png" Grid.Column="4"></Image>
<Image Source="trash.jpg" Grid.Column="5"></Image>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage.Content>
</ContentPage>

As Jason said: If you specify the VM in XAML it will create a new instance for each page. They are totally different.
How can I use the same viewmodel across multiple pages?
There are many ways to do it.
For example, you can define/create a static ViewModel in App.cs:
public partial class App : Application
{
public static DebtViewModel sharedViewModel { get; set; }
public App()
{
InitializeComponent();
MainPage = new MainPage();
createViewModel();
}
public void createViewModel() {
sharedViewModel = new DebtViewModel();
}
public class DebtViewModel {
}
}
Then in other page, you can set this ViewModel as page's bindingContext:
public partial class Page1 : ContentPage
{
public Page1()
{
InitializeComponent();
this.BindingContext = App.sharedViewModel;
}
}
Pass the instance to the new page on the constructor in also a solution.

Related

CollectionView items animation

I'm creating application with chat function. I made simple 'typing indicator' that shows new item in collectionView (Label) with text 'User is typing...'. So now i would like to animate this Label or add some animation like 3 dots that indicates user is typing. Is it somehow possible to make something like this? Any help appreciated, Thank you.
#EDIT
Code below describes my Chat layout:
<ContentPage.Content>
<StackLayout x:Name="content_stackLayout">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="100" />
</Grid.RowDefinitions>
<CollectionView
x:Name="chat_collectionView"
Grid.Row="0"
VerticalOptions="Start"
HorizontalOptions="Center"
ItemSizingStrategy="MeasureAllItems"
SelectionMode="None"
ItemsSource="{Binding Messages}"
ItemsUpdatingScrollMode="KeepLastItemInView"
>
<CollectionView.ItemTemplate>
<DataTemplate>
<StackLayout Orientation="Vertical" VerticalOptions="FillAndExpand">
<StackLayout Orientation="Horizontal" HorizontalOptions="{Binding messageAlignment}" Margin="30,5,30,5">
<Image
Source="{Binding image}"
Margin="{Binding imageMargin}"
HeightRequest="40"
WidthRequest="40"
Aspect="AspectFit" />
<Frame
BorderColor="Black"
CornerRadius="{Binding cornerRadius}"
BackgroundColor="{Binding kolorWiadomosci}"
Margin="{Binding messageMargin}">
<Label
Text="{Binding message}"
FontAttributes="{Binding textAttribute}"
x:Name="label"
FontSize="Title"
VerticalOptions="CenterAndExpand" />
</Frame>
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<StackLayout
Grid.Row="1"
Orientation="Horizontal"
x:Name="sendMessage_stackLayout"
HeightRequest="80"
Padding="8"
>
<Entry
Margin="10,10,0,5"
Placeholder="your message..."
ClassId="message_entry"
x:Name="message_entry_label"
HorizontalOptions="FillAndExpand"
ClearButtonVisibility="WhileEditing"
Keyboard="Chat"
ReturnType="Send"
TextColor="Black"
BackgroundColor="#2596be"
/>
<Button
WidthRequest="200"
HeightRequest="30"
Text="Send"
FontSize="Title"
x:Name="button_send_label"
HorizontalOptions="End"
Clicked="Button_Clicked"
BorderWidth="5"
BorderColor="Black"
CornerRadius="5"
/>
</StackLayout>
</Grid>
</StackLayout>
</ContentPage.Content>
I've got binding with viewModel which receives messages from another App with SignalR, creates a new messages and adds them to List called "Messages" like below:
public class Message
{
public string message{ get; set; }
//public Thickness messageMargin{ get; set; }
public string image{ get; set; }
//public Thickness imageMargin{ get; set; }
public FontAttributes textAttribute{ get; set; }
public string author{ get; set; }
public LayoutOptions messageAlignment{ get; set; }
public Color textColor{ get; set; }
public double cornerRadius { get; set; }
}
So now when another person in second App is typing, it fires SignalR boolean method that my 'Chat App' receives. If UserTyping = true - App adds new message saying 'User is typing'. I would like to animate it somehow or if not possible, develop another solution for this behaviour.

How to open a page from a class?

I am trying to create a little application using MVVM. I would like to open a second page that scan a QR code and then back the value of the QR code to the main page.
I have this code:
Main view:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="QRScannerXamarinForms.Views.MainPageView"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
xmlns:vm="clr-namespace:QRScannerXamarinForms.ViewModels">
<ContentPage.BindingContext>
<vm:MainPageViewModel/>
</ContentPage.BindingContext>
<StackLayout>
<Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
<Label Text="Barcode Sample" HorizontalTextAlignment="Center" TextColor="White" FontSize="36" />
</Frame>
<Button x:Name="ucBtnEscanear" Text="Escanear"
Command="{Binding EscanearCommand}"/>
</StackLayout>
</ContentPage>
Main view model:
private INavigationService _navigationService;
public ICommand EscanearCommand { get; private set; }
private void Escanear()
{
string miCodigoQr = _navigationService.AbrirPaginaEscaner();
}
Second view:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="QRScannerXamarinForms.Views.ScannerView"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
xmlns:vm="clr-namespace:QRScannerXamarinForms.ViewModels">
<ContentPage.BindingContext>
<vm:ScannerViewModel/>
</ContentPage.BindingContext>
<ContentPage.Content>
<StackLayout>
<Frame BackgroundColor="#2196F3" Padding="24" CornerRadius="0">
<Label Text="Barcode Sample" HorizontalTextAlignment="Center" TextColor="White" FontSize="36" />
</Frame>
<Label x:Name="ucScanResultText" />
<zxing:ZXingScannerView x:Name="ucZXingScannerView" IsScanning="True" IsAnalyzing="True" Result="{Binding CodigoQr}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Second view model:
class ScannerViewModel : BaseViewModel
{
private string _codigoQr;
public string CodigoQr
{
get { return _codigoQr; }
set { _codigoQr = value; }
}
}
Interface to open pages:
namespace QRScannerXamarinForms.Services
{
interface INavigationService
{
string AbrirPaginaEscaner();
}
}
Implementation of the interface that allows navigation.
namespace QRScannerXamarinForms.Services
{
class ViewNavigationService : INavigationService
{
public string AbrirPaginaEscaner()
{
ScannerView miScannerView = new ScannerView();
ScannerViewModel miScannerViewModel = miScannerView.BindingContext as ScannerViewModel;
Application.Current.MainPage.Navigation.PushModalAsync(miScannerView);
return miScannerViewModel.CodigoQr;
}
}
}
But in the implementation of the interface, the second page is not shown. So this line doesn't work:
Application.Current.MainPage.Navigation.PushModalAsync(miScannerView);
How could I open from this class?
Thanks.

How to set BindingContext of MasterDetailPage.Master

I have a MasterDetailPage.Master and a Login page. After the login I call a WebService that returns a filled class to me, and its working, even the BindingContext is getting the values, but the fields on the Page are empty. How do I set the binding context of the MasterDetailPage.Master if it is rendering before the Login page?
This is for a profile page in the MasterDetailPage.Master, using a WebService to fill the binding. I already tried to call a new instance of the MasterDetailPage on the OnDesappearing of the Login page, but not success.
MainPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:HCTaNaMao.Views"
x:Class="HCTaNaMao.Views.MainPage">
<MasterDetailPage.Master>
<views:InformacoesUsuario />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<NavigationPage.Icon>
<OnPlatform x:TypeArguments="FileImageSource">
<On Platform="iOS" Value="tab_feed.png"/>
</OnPlatform>
</NavigationPage.Icon>
<x:Arguments>
<views:Menu />
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
MasterDetailPage.Master.xaml
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="HCTaNaMao.Views.InformacoesUsuario"
Title="Dados do Usuário">
<TabbedPage.Children>
<ContentPage Title="Usuário">
<StackLayout Padding="0,50,0,0">
<Image BackgroundColor="LightGray" HorizontalOptions="Center" Source="HC_logo.png"></Image>
<Frame
OutlineColor="Silver"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Fill"
Margin="15">
<StackLayout
HorizontalOptions="Center"
VerticalOptions="Center">
<Label x:Name="lblNome" Text="{Binding nome}" FontSize="18" HorizontalTextAlignment="Center"></Label>
<BoxView Color="Gray" HeightRequest="1" HorizontalOptions="Fill"/>
<Label x:Name="lblProntuario" Text="{Binding prontuario}" FontSize="18" HorizontalTextAlignment="Center"></Label>
<BoxView Color="Gray" HeightRequest="1" HorizontalOptions="Fill"/>
<Button x:Name="btnEditar" Text="Perfil" TextColor="White" WidthRequest="110"
HorizontalOptions="Center" BackgroundColor="SteelBlue" BorderRadius="20"/>
</StackLayout>
</Frame>
</StackLayout>
</ContentPage>
<ContentPage Title="Perfil">
<Frame
OutlineColor="Silver"
VerticalOptions="CenterAndExpand"
HorizontalOptions="Fill"
Margin="15">
<StackLayout>
<TableView>
<TableRoot>
<TableSection Title="Dados Pessoais">
<EntryCell x:Name="cellNome" Placeholder="Nome"
Text="{Binding nome}" IsEnabled="True"></EntryCell>
<EntryCell Placeholder="Data de Nascimento" x:Name="cellNasc"
Text="{Binding data_nascimento}" IsEnabled="True"></EntryCell>
<EntryCell Placeholder="CPF" Keyboard="Numeric" x:Name="cellCpf"
Text="{Binding cpf}" IsEnabled="True"></EntryCell>
<EntryCell Placeholder="CNS" Keyboard="Numeric" x:Name="cellCns"
Text="{Binding cns}" IsEnabled="True"></EntryCell>
</TableSection>
</TableRoot>
</TableView>
<Button Text="Editar"
IsVisible="False">
</Button>
<Button x:Name="btnSalvar"
Text="Salvar"
IsVisible="True" TextColor="White" WidthRequest="110"
HorizontalOptions="Center" BackgroundColor="SteelBlue" BorderRadius="20"></Button>
</StackLayout>
</Frame>
</ContentPage>
</TabbedPage.Children>
</TabbedPage>
MaterDetailPage.xaml.cs
namespace HCTaNaMao.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class InformacoesUsuario : TabbedPage
{
HCTMWebService service = new HCTMWebService();
HCTMPacienteDTO paciente;
public InformacoesUsuario ()
{
InitializeComponent();
btnEditar.Command = new Command(() => this.CurrentPage = this.Children[1]);
btnSalvar.Command = new Command(() => this.CurrentPage = this.Children[0]);
paciente = service.InformacoesPaciente(Login.seq_cliente);
BindingContext = paciente;
}
}
}
I expect MasterPage fields are filled by the Binding
How do I set the binding context of the MasterDetailPage.Master if it is rendering before the Login page?
About binding context of MasterDetailedPage.Master, I do one sample, you can take a look:
MainPage:
<MasterDetailPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MasterDetailPageNavigation;assembly=MasterDetailPageNavigation"
x:Class="MasterDetailPageNavigation.MainPage">
<MasterDetailPage.Master>
<local:MasterPage x:Name="masterPage" />
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<NavigationPage>
<x:Arguments>
<local:ContactsPage />
</x:Arguments>
</NavigationPage>
</MasterDetailPage.Detail>
</MasterDetailPage>
public partial class MainPage : MasterDetailPage
{
public MainPage()
{
InitializeComponent();
masterPage.listView.ItemSelected += OnItemSelected;
if (Device.RuntimePlatform == Device.UWP)
{
MasterBehavior = MasterBehavior.Popover;
}
}
void OnItemSelected(object sender, SelectedItemChangedEventArgs e)
{
var item = e.SelectedItem as MasterPageItem;
if (item != null)
{
Detail = new NavigationPage((Page)Activator.CreateInstance(item.TargetType));
masterPage.listView.SelectedItem = null;
IsPresented = false;
}
}
}
MasterPage:
I don't understand why your masterPage is TabbedPage, I think it should be contentpage,that has Listview to display detailed page title.
<ContentPage
x:Class="MasterDetailPageNavigation.MasterPage"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="using:MasterDetailPageNavigation"
Title="Personal Organiser"
Padding="0,40,0,0"
IconImageSource="hamburger.png">
<StackLayout>
<ListView
x:Name="listView"
x:FieldModifier="public"
ItemsSource="{Binding items}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid Padding="5,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="30" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Source="{Binding IconSource}" />
<Label Grid.Column="1" Text="{Binding Title}" />
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
public partial class MasterPage : ContentPage
{
public ObservableCollection<MasterPageItem> items { get; set; }
public MasterPage()
{
InitializeComponent();
//load data from service or other.
items = new ObservableCollection<MasterPageItem>()
{
new MasterPageItem(){ Title="Contacts", IconSource="contacts.png",TargetType=typeof(ContactsPage)},
new MasterPageItem(){Title="TodoList",IconSource="todo.png",TargetType=typeof(TodoListPage)},
new MasterPageItem(){Title="Reminders",IconSource="reminders.png",TargetType=typeof(ReminderPage)}
};
this.BindingContext = this;
}
}
About MasterDetailedPage, I suggest you can take a look:
https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/navigation/master-detail-page

View IsEnabled Property is not working on Xamarin Forms

Here is my Listview
Inside Listview button IsEnabled Property not working,IsEnabled False not working.
I followed This step but still its not working
https://forums.xamarin.com/discussion/47857/setting-buttons-isenabled-to-false-does-not-disable-button
Inside My ViewModel
OrderItems=PopuldateOrders();// getting List Items
<ListView x:Name="OrderItems" VerticalOptions="Fill"
BackgroundColor="White" HasUnevenRows="True"
SeparatorVisibility="None" ItemsSource="{Binding OrderItems}">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ContentView BackgroundColor="White">
<Grid BackgroundColor="Transparent" Margin="0" VerticalOptions="FillAndExpand" x:Name="Item">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*"/>
<ColumnDefinition Width="18*"/>
<ColumnDefinition Width="18*"/>
<ColumnDefinition Width="17*"/>
<ColumnDefinition Width="20*"/>
<ColumnDefinition Width="17*"/>
</Grid.ColumnDefinitions>
<Label Text="{Binding PullSheetId}" Grid.Row="0" IsVisible="False"/>
<controls:CheckBox Checked="{Binding IsChecked}" Grid.Row="0" Grid.Column="0" IsVisible="{Binding IsEnableShipBtn}" Scale=".8"/>
<Label Text="{Binding KitSKU}" Grid.Row="0" Grid.Column="1"
HorizontalTextAlignment="Center" VerticalOptions="Center" FontSize="Small" TextColor="Black"/>
<Label Text="{Binding SKU}" Grid.Row="0" Grid.Column="2"
HorizontalTextAlignment="Center" VerticalOptions="Center" FontSize="Small" TextColor="{Binding ItemColor}"/>
<Label Text="{Binding ReqPackQty}" Grid.Row="0" Grid.Column="3"
HorizontalTextAlignment="Center" VerticalOptions="Center" FontSize="Small" TextColor="Black"/>
<local:EntryStyle Scale=".6" Text="{Binding ScanQuantity}" Grid.Row="0" Keyboard="Numeric"
Grid.Column="4" HorizontalTextAlignment="Center"
VerticalOptions="Center" Placeholder="Qty" IsEnabled="True" x:Name="QtyEntry"
>
<local:EntryStyle.Behaviors>
<eventToCommand:EventToCommandBehavior EventName="TextChanged"
Command="{Binding Source={x:Reference OrderItems}, Path=BindingContext.ChangeItemQty}"
CommandParameter="{Binding Source={x:Reference Item}, Path=BindingContext}"
/>
</local:EntryStyle.Behaviors>
</local:EntryStyle>
<Button Text="Ship" Scale=".6" Grid.Row="0" Grid.Column="5"
VerticalOptions="Center" BackgroundColor="#6eb43a" TextColor="White"
BorderRadius="20" CornerRadius="20" BorderColor="{Binding isError}" BorderWidth="3"
MinimumWidthRequest="60"
x:Name="ShipBtn"
Command="{Binding Source={x:Reference OrderItems}, Path=BindingContext.SubmitSingleItem}"
IsEnabled="{Binding IsEnableShipBtn}" IsVisible="{Binding IsEnableShipBtn}"
CommandParameter="{Binding .}"
/>
</Grid>
</ContentView>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.Behaviors>
<eventToCommand:EventToCommandBehavior EventName="ItemTapped" Command="{Binding PackerItemsItemTapped}"/>
</ListView.Behaviors>
</ListView>
How to solve this?
You could achieve CanExecute method in ICommand to replace the IsEnabled property of Button. You could refer to my demo.
This is a GIF of my demo.
Firstly, You could see MainPage.xaml. Binding the model view and set command for Buttons.
<?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:local="clr-namespace:TestDemo"
x:Class="TestDemo.MainPage">
<!--BindingContext from ButtonExecuteViewModel -->
<StackLayout>
<StackLayout.BindingContext>
<local:ButtonExecuteViewModel/>
</StackLayout.BindingContext>
<Button
Text="click me to enable following button"
Command="{Binding NewCommand}"/>
<Button
Text="Cancel"
Command="{Binding CancelCommand}"/>
</StackLayout>
Here is View Model ButtonExecuteViewModel.cs. You could see the construction method of ButtonExecuteViewModel, it set the execute and canExecute to acheve isEnable of Button.
public class ButtonExecuteViewModel : INotifyPropertyChanged
{
bool isEditing;
public event PropertyChangedEventHandler PropertyChanged;
public ButtonExecuteViewModel()
{
NewCommand = new Command(
execute: () =>
{
IsEditing = true;
RefreshCanExecutes();
},
canExecute: () =>
{
return !IsEditing;
});
CancelCommand = new Command(
execute: () =>
{
IsEditing = false;
RefreshCanExecutes();
},
canExecute: () =>
{
return IsEditing;
});
}
void RefreshCanExecutes()
{
(NewCommand as Command).ChangeCanExecute();
(CancelCommand as Command).ChangeCanExecute();
}
public ICommand NewCommand { private set; get; }
public ICommand CancelCommand { private set; get; }
public bool IsEditing
{
private set { SetProperty(ref isEditing, value); }
get { return isEditing; }
}
//Determine if it can be executed
bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
{
if (Object.Equals(storage, value))
return false;
storage = value;
OnPropertyChanged(propertyName);
return true;
}
protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I tried all the answers here and nothing worked, I only solved creating a custom button component:
CustomButtonView.xaml
<Button xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CustomComponents.CustomButton.CustomButtonView"
FontAttributes="Bold"
TextColor="White"
FontSize="20"
TextTransform="Uppercase"
CornerRadius="20"
WidthRequest="200"
HorizontalOptions="Center" />
CustomButtonView.xaml.cs: Here lives the magic of the custom IsEnabled
using System.Windows.Input;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace CustomComponents.CustomButton
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class CustomButtonView
{
#region constructors
public CustomButtonView()
{
InitializeComponent();
BackgroundColor = Color.Blue;
Clicked += (_, args) =>
{
if (IsEnabled) Command?.Execute(args);
};
}
#endregion
#region Command
public new static readonly BindableProperty CommandProperty = BindableProperty.Create(
nameof(Command),
typeof(ICommand),
typeof(CustomButtonView));
public new ICommand? Command
{
get => (ICommand)GetValue(CommandProperty);
set => SetValue(CommandProperty, value);
}
#endregion
#region IsEnabled
public new static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(
nameof(IsEnabled),
typeof(bool),
typeof(CustomButtonView),
true,
propertyChanged: (bindable, _, newValue) =>
{
var component = (CustomButtonView)bindable;
if ((bool)newValue)
{
component.BackgroundColor = Color.Blue;
}
else
{
component.BackgroundColor = Color.Red;
}
});
public new bool IsEnabled
{
get => (bool)GetValue(IsEnabledProperty);
set => SetValue(IsEnabledProperty, value);
}
#endregion
}
}
Now you can use it like any regular button in your XAML:
<customButton:CustomButtonView Text="Button enabled"
Command="{Binding SomeCommand}"
IsEnabled="True"/>
<customButton:CustomButtonView Text="Button disabled"
Command="{Binding SomeCommand}"
IsEnabled="False"/>

Serialize Class Xamarin.Forms

I’m trying to serialize class but I can’t do it.
I have a class below:
public class DadosTitulo
{
public string nome { get; set; }
public string numeroCpfCnpj { get; set; }
public string logradouro { get; set; }
public string numero { get; set; }
public string complemento { get; set; }
public string bairro { get; set; }
public string cep { get; set; }
public string municipio { get; set; }
public string uf { get; set; }
public double valor { get; set; }
public string numeroDocumento { get; set; }
public string dataVencimento { get; set; }
public string celularDestino { get; set; }
public bool registroProducao { get; set; }
}
And in my MainPage.xaml.cs I have:
private async void btnAdicionar_Clicked(object sender, EventArgs e)
{
var retorno = "";
var titulo = new DadosTitulo
{
nome = txtNome.Text,
numeroCpfCnpj = txtNumeroCpfCnpj.Text,
logradouro = txtLogradouro.Text,
numero = txtNumero.Text,
complemento = txtComplemento.Text,
bairro = txtBairro.Text,
cep = txtCep.Text,
municipio = txtMunicipio.Text,
uf = txtUF.Text,
valor = Convert.ToDouble(txtValor.Text),
numeroDocumento = txtNumeroDocumento.Text,
dataVencimento = DataVencimento.Date.ToString("dd/MM/yyyy"),
celularDestino = txtDddCelularDestino.Text + txtNumCelularDestino.Text,
registroProducao = RegistraProducao
};
var registroService = new RegistroBoletoService();
retorno = registroService.RegistrarBoleto(titulo);
await DisplayAlert("Json", retorno, "OK");
}
Property Values from MainPage.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:local="clr-namespace:AppRegistraBoletoXF"
x:Class="AppRegistraBoletoXF.MainPage">
<StackLayout Orientation="Vertical">
<StackLayout>
<Label Text="Registra Boleto" TextColor="Indigo" FontSize="Medium" />
</StackLayout>
<StackLayout>
<Label Text="Informe os dados do Título:" TextColor="Black" FontSize="Small" />
</StackLayout>
<StackLayout>
<Entry x:Name="txtNome" Placeholder="Nome" HorizontalOptions="Start"
VerticalOptions="StartAndExpand" HeightRequest="35" WidthRequest="300" FontSize="Small"/>
<Entry x:Name="txtNumeroCpfCnpj" Placeholder="CPF/CNPJ" HorizontalOptions="Start"
VerticalOptions="StartAndExpand" HeightRequest="35" WidthRequest="300" FontSize="Small" />
<StackLayout Orientation="Horizontal">
<Entry x:Name="txtLogradouro" Placeholder="Logradouro" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="160" FontSize="Small" />
<Entry x:Name="txtNumero" Placeholder="Número" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="50" FontSize="Small" />
<Entry x:Name="txtComplemento" Placeholder="Complemento" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="90" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Entry x:Name="txtBairro" Placeholder="Bairro" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="180" FontSize="Small" />
<Entry x:Name="txtCep" Placeholder="CEP" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="120" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Entry x:Name="txtMunicipio" Placeholder="Município" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="250" FontSize="Small" />
<Entry x:Name="txtUF" Placeholder="UF" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="50" FontSize="Small" />
</StackLayout>
<StackLayout Orientation="Horizontal">
<Entry x:Name="txtDddCelularDestino" Placeholder="DDD" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="50" FontSize="Small" />
<Entry x:Name="txtNumCelularDestino" Placeholder="Celular Destino" HorizontalOptions="StartAndExpand" VerticalOptions="Start"
HeightRequest="35" WidthRequest="250" FontSize="Small" />
</StackLayout>
<Entry x:Name="txtNumeroDocumento" Placeholder="Número do Título" HorizontalOptions="Start"
VerticalOptions="StartAndExpand" HeightRequest="35" WidthRequest="300" FontSize="Small"/>
<Entry x:Name="txtValor" Placeholder="Valor do Título" HorizontalOptions="Start"
VerticalOptions="StartAndExpand" HeightRequest="35" WidthRequest="300" FontSize="Small"/>
<StackLayout Orientation="Horizontal">
<Label Text="Registro em Produção: " TextColor="Black" FontSize="Small" HorizontalOptions="Start"
VerticalOptions="StartAndExpand" />
<DatePicker DateSelected="DataSelecionada" HorizontalOptions="Start" VerticalOptions="StartAndExpand">
<DatePicker.Format>dd/MM/yyyy</DatePicker.Format>
</DatePicker>
</StackLayout>
<StackLayout Orientation="Horizontal">
<Label Text="Registro em Produção: " TextColor="Black" FontSize="Small" HorizontalOptions="Center"
VerticalOptions="StartAndExpand" />
<Switch IsToggled="False" Toggled="RegistrarProducao" HorizontalOptions="Center"
VerticalOptions="StartAndExpand" />
</StackLayout>
<Button HorizontalOptions="FillAndExpand" VerticalOptions="StartAndExpand" HeightRequest="40" Text="Registrar Título"
Clicked="btnAdicionar_Clicked" FontSize="Small"/>
</StackLayout>
</StackLayout>
</ContentPage>
In RegistroBoletoService:
public string RegistrarBoleto(DadosTitulo dadosTitulo)
{
var data = JsonConvert.SerializeObject(dadosTitulo);
return data;
}
data allways return “{}”:
I have made a test calling RegistroBoletoService from Console Project, in the same Solution, and the result was as expected: data contains json
The interesting point that I noticed: when I have instantiated the class in MainPage.xaml.cs the behavior was diferent from Console Project, with Non-Public Members in the class:
Console Instantiate:
I think that this is the problem, anyone have an idea what is it happening ? Why when I have instantiated the class in the MainPage I get different behavior from the Console ?
Thanks a lot and sorry my English.
PS.: Project in .NET Standard; I’m not using MVVM in this case; I tried testing with the linker SDK Assemblies Only and None.

Resources