toolbar items xamarin.forms disappeared - xaml

I want to add toolbar item to save the user input. I used the contentpage.toolbar items as shown in the code below:
<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="firstXamarin.HistoryPage">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add"
Order="Primary"
Priority="0"
Clicked="Add_OnClicked" />
</ContentPage.ToolbarItems>
<ContentPage.Content>
<StackLayout Margin="30,30">
<Entry x:Name="UsernameEntry" Placeholder="username" VerticalOptions="Center" Height="50" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
the toolbar item and the toolbar are missed. I followed these solutions but they do not work:
Toolbar item not showing in xamarin forms
ToolbarItem are not shown
this my .cs file for the page:
public HistoryPage()
{
InitializeComponent();
}
private void Add_OnClicked(object sender, EventArgs e)
{
Post post = new Post()
{
Username = UsernameEntry.Text
};
SQLiteConnection conn = new SQLiteConnection(App.DatabaseLocation);
conn.CreateTable<Post>();
int rows = conn.Insert(post);
conn.Close();
if (rows > 0)
{
DisplayAlert("Success", "the data inserted successfully", "ok");
}
else
{
DisplayAlert("failure", "the data are not inserted ", "ok");
}
}
Note:
I have read that i would use navigation page but I did not find xaml example for NavigationPage implementation
Below is the code of tabbed page :
<TabbedPage 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:firstXamarin;assembly=firstXamarin"
mc:Ignorable="d"
x:Class="firstXamarin.MainPage">
<TabbedPage.ToolbarItems></TabbedPage.ToolbarItems>
<local:ReportPage Title="Report" />
<local:HistoryPage Title="History"/>
</TabbedPage>
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
}
}
}
App Page Code :
<Application.Resources>
<Color x:Key="ButtonColor">CornflowerBlue</Color>
<Color x:Key="EntryColor">Gainsboro</Color>
<Style TargetType="Button">
<Setter Property="BackgroundColor" Value="{StaticResource ButtonColor}"/>
<Setter Property="TextColor" Value="{StaticResource EntryColor}"/>
</Style>
</Application.Resources>
</Application>
public partial class App : Application
{
public static string DatabaseLocation = string.Empty;
public App()
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
}
public App(string dblocation)
{
InitializeComponent();
MainPage = new NavigationPage(new MainPage());
DatabaseLocation = dblocation;
}
protected override void OnStart()
{
}
protected override void OnSleep()
{
}
protected override void OnResume()
{
}
}

If the MainPage of App is a TabbedPage .
in App.xaml.cs
MainPage = new MainPage()
in MainPage
Set the children page as NavigationPage
<TabbedPage.Children>
<NavigationPage Title="xxx">
<x:Arguments>
<local:HistoryPage />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="xxx">
<x:Arguments>
<local:ReportPage />
</x:Arguments>
</NavigationPage>
</TabbedPage.Children>

Related

XAML Data Binding value not refreshing inside two ContentPages

I am trying to output a value from my object to two different entries. Both entries are on the same view but in different ContentPages as follows:
<?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="myApp.Views.ViewTabs.ViewHome"
xmlns:localTabs="clr-namespace:myApp.Views.ViewTabs"
xmlns:localObjPages="clr-namespace:myApp.Objects"
>
<ContentPage Title="PageOne">
<ContentPage.BindingContext>
<localObjPages:PagesObj/>
</ContentPage.BindingContext>
<ScrollView>
<StackLayout>
<Entry
x:Name="EntryOne" Text="{Binding BananaCount}"/>
<Entry
x:Name="EntryTwo" Text="{Binding BananaCount}"/>
</StackLayout>
</ScrollView>
</ContentPage>
<ContentPage Title="PageTwo">
<ContentPage.BindingContext>
<localObjPages:PagesObj/>
</ContentPage.BindingContext>
<ScrollView>
<StackLayout>
<Entry
x:Name="EntryThree" Text="{Binding BananaCount}"/>
</StackLayout>
</ScrollView>
</ContentPage>
</TabbedPage>
My Model:
public string BananaCount
{
get { return _bananaCount; }
set
{
if (_bananaCount != value)
{
_bananaCount = value;
NotifyPropertyChanged("BananaCount");
}
}
}
The object is updated and returned in EntryOne or in EntryTwo when I change it either in EntryOne or in EntryTwo. However, it is not updated in EntryThree. Why is this? Am I Binding this correctly? Thank you.
The object is updated and returned in EntryOne or in EntryTwo when I change it either in EntryOne or in EntryTwo. However, it is not updated in EntryThree. Why is this? Am I Binding this correctly?
Do one sample about TabbedPage, assign datasource for TabbedPage, not contentpage, that you can take a look:
<TabbedPage
x:Class="FormsSample.tabbedpage.TabbedPage6"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:FormsSample.tabbedpage">
<!--Pages can be added as references or inline-->
<ContentPage Title="PageOne">
<ScrollView>
<StackLayout>
<Entry x:Name="EntryOne" Text="{Binding str}" />
<Entry x:Name="EntryTwo" Text="{Binding str}" />
<Button
x:Name="btn1"
Clicked="btn1_Clicked"
Text="change data" />
</StackLayout>
</ScrollView>
</ContentPage>
<ContentPage Title="PageTwo">
<ScrollView>
<StackLayout>
<Entry x:Name="EntryThree" Text="{Binding str}" />
</StackLayout>
</ScrollView>
</ContentPage>
public partial class TabbedPage6 : TabbedPage
{
public tabclass tabc { get; set; }
public TabbedPage6()
{
InitializeComponent();
tabc = new tabclass();
this.BindingContext = tabc;
}
private void btn1_Clicked(object sender, EventArgs e)
{
tabc.str = "this is test!";
}
}
public class tabclass:ViewModelBase
{
private string _str;
public string str
{
get { return _str; }
set
{
_str = value;
RaisePropertyChanged("str");
}
}
}
The ViewModel is one class that implement INotifyPropertyChanged.
public class ViewModelBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}

Xamarin - Binding command inside stacklayout datatemplate not working

Trying to fire a command inside a stacklayout with itemssource. I wonder why the NavigateToProductListViewShopTappedCommand is not getting fired.
Tried multiple command approaches:
1)
Command="{Binding Source={RelativeSource AncestorType={x:Type local:MyShopsListViewModel}}, Path=NavigateToProductListViewShopTappedCommand}"
Command="{Binding BindingContext.NavigateToProductListViewShopTappedCommand, Source={x:Reference Page}}"
Command="{Binding Path=BindingContext.NavigateToProductListViewShopTappedCommand, Source={x:Reference Page}}"
None are not working
Code:
<?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:controls="clr-namespace:BoerPlaza.Controls.Shop"
xmlns:local="clr-namespace:BoerPlaza.ViewModels"
xmlns:behaviors="clr-namespace:BoerPlaza.Behaviors"
x:Class="BoerPlaza.Views.Shop.MyShopsPage"
x:Name="Page"
Title="Mijn winkels">
<ContentPage.Content>
<ScrollView>
<StackLayout Margin="{StaticResource margin-side-std}"
Padding="{StaticResource padding-top-bottom-std}"
BindableLayout.ItemsSource="{Binding Shops}">
<BindableLayout.ItemTemplate>
<DataTemplate>
<controls:ShopCardTemplateView Shop="{Binding .}"
ControlTemplate="{StaticResource ShopCardTemplateView}">
<controls:ShopCardTemplateView.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1"
Command="{Binding Source={RelativeSource AncestorType={x:Type local:MyShopsListViewModel}}, Path=NavigateToProductListViewShopTappedCommand}"
CommandParameter="{Binding .}">
<!--Command="{Binding BindingContext.NavigateToProductListViewShopTappedCommand, Source={x:Reference Page}}"-->
</TapGestureRecognizer>
</controls:ShopCardTemplateView.GestureRecognizers>
</controls:ShopCardTemplateView>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
Code behind
public partial class MyShopsPage : ContentPage
{
private readonly MyShopsListViewModel _viewModel;
public MyShopsPage()
{
InitializeComponent();
BindingContext = _viewModel = new MyShopsListViewModel(App.ShopDataStore, App.DialogService);
_viewModel.LoadShopsOnUserIdCommand.Execute("B22698B8-42A2-4115-9631-1C2D1E2AC5F7");
}
protected override void OnAppearing()
{
base.OnAppearing();
_viewModel.OnAppearing();
}
}
ViewModel:
[QueryProperty(nameof(UserId), nameof(UserId))]
public class MyShopsListViewModel : BaseViewModel
{
private string _userId;
private ObservableCollection<ShopDbViewModel> _shops;
private readonly IShopDataStore _shopDataStore;
private readonly IDialogService _dialogService;
public ObservableCollection<ShopDbViewModel> Shops
{
get
{
return _shops;
}
set
{
_shops = value;
OnPropertyChanged(nameof(Shops));
}
}
public void OnAppearing()
{
IsBusy = true;
}
public ICommand LoadShopsOnUserIdCommand { get; set; }
public ICommand NavigateToProductListViewShopTappedCommand { get; set; }
public MyShopsListViewModel(IShopDataStore shopDataStore, IDialogService dialogService)
{
this._shopDataStore = shopDataStore;
this._dialogService = dialogService;
Shops = new ObservableCollection<ShopDbViewModel>();
LoadShopsOnUserIdCommand = new Command<string>(async (string userId) => await ExecuteLoadShopsOnUserId(userId));
NavigateToProductListViewShopTappedCommand = new Command<ShopDbViewModel>(async (ShopDbViewModel shop) => await ExecuteNavigateToProductListViewShopTappedCommandAsync(shop));
}
private async Task ExecuteNavigateToProductListViewShopTappedCommandAsync(ShopDbViewModel shop)
{
if (shop == null)
return;
await Shell.Current.GoToAsync($"{nameof(ProductsPage)}?{nameof(MyProductsListViewModel.ShopId)}={shop.Id}");
}
public string UserId
{
get
{
return _userId;
}
set
{
_userId = value;
LoadShopsOnUserIdCommand.Execute(value);
}
}
private async Task ExecuteLoadShopsOnUserId(string userId)
{
var current = Connectivity.NetworkAccess;
if (current == NetworkAccess.Internet)
{
try
{
Shops.Clear();
var shops = await _shopDataStore.GetShopOnUserIdAsync(userId);
foreach(var shop in shops)
{
Shops.Add(shop);
}
}
catch (Exception ex)
{
await _dialogService.ShowDialog(ex.Message, "An error has occurred", "OK");
}
finally
{
IsBusy = false;
}
}
else
{
await _dialogService.ShowDialog("No active internet connection", "Connection error", "OK");
IsBusy = false;
}
}
}
If you define the ICommand in the ViewModel directly , you could set the binding path like following
Command="{Binding Path=BindingContext.NavigateToProductListViewShopTappedCommand, Source={x:Reference Page}}"
I've found the problem
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:ffimage="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms"
xmlns:customcontrols="clr-namespace:BoerPlaza.Controls"
x:Class="BoerPlaza.Controls.Shop.ShopCardTemplateView">
<ContentView.Resources>
<ControlTemplate x:Key="ShopCardTemplateView">
<!-- Card Header -->
<!-- for displaying products and categories on homepage -->
<StackLayout Spacing="1"
HorizontalOptions="FillAndExpand"
Margin="{StaticResource margin-card}">
<!-- On click - shows the product detail view page -->
<StackLayout.GestureRecognizers>
<TapGestureRecognizer NumberOfTapsRequired="1" />
</StackLayout.GestureRecognizers>
<!-- Image frame -->
<Frame BackgroundColor="{StaticResource image-box-color}"
CornerRadius="0"
HasShadow="False"
HorizontalOptions="FillAndExpand"
VerticalOptions="FillAndExpand"
HeightRequest="100">
<!-- Product Image -->
....
As you can see this is the control template I'm using for the MyShopsPage. This is a shop card. Inside this shop card I already had an StackLayout.GestureRecognizers. Somehow when I was clicking on the control template, I was actually clicking on this.
I always thought everything flows from top to bottom in events, but this seems different. Something that is on top on something else does not mean anything in xaml.

Xamarin forms Add button in TabbedPage

I have a question. I created the following TabbedPage:
<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage 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:views="clr-namespace:MyApp.Views"
mc:Ignorable="d"
x:Class="MyApp.Views.MainPage"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core"
android:TabbedPage.ToolbarPlacement="Bottom"
BarBackgroundColor="White"
BarTextColor="Black"
android:TabbedPage.BarItemColor="#B2B2B2"
android:TabbedPage.BarSelectedItemColor="#56D7A5"
android:TabbedPage.IsSwipePagingEnabled="False">
<TabbedPage.Children>
<NavigationPage Title="page1" IconImageSource="navbar_page1">
<x:Arguments>
<views:page1 NavigationPage.HasNavigationBar="False" />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="page2" IconImageSource="navbar_page2">
<x:Arguments>
<views:page2 NavigationPage.HasNavigationBar="False" />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="page3" IconImageSource="navbar_page3">
<x:Arguments>
<views:page3 NavigationPage.HasNavigationBar="False" />
</x:Arguments>
</NavigationPage>
</TabbedPage>
Now on every page I have added this custom FabMenu like this:
<c:FloatingMenu Margin="0, 0, 10, 10" BGColor="#56D7A5" OpenIcon="openFab_icon" CloseIcon="closeFab_icon"
AbsoluteLayout.LayoutBounds=".95,.95" AbsoluteLayout.LayoutFlags="PositionProportional">
<c:FloatingButton x:Name="btnAddHomework" BGColor="#59E1FF" IconSrc="add_homework_icon" OnClickCommand="{Binding btnAddHomeworkCommand}" />
<c:FloatingButton x:Name="btnAddDeadline" BGColor="#0FF1A0" IconSrc="add_deadline_icon"/>
<c:FloatingButton x:Name="btnAddTest" BGColor="#5988FF" IconSrc="add_test_icon"/>
</c:FloatingMenu>
The problem is that every page has his own FabMenu, so you see it dissapear and reappear on every page, so my question is: Is there some kind of root view that overlays all the tabs in the TabbedPage?
Please let me know how I do that!
Disclaimer
I came up with a way to create the effect wanted using only pure Xamarin.Forms. Read along and pay attention to the tricky parts of the solution.
Abstract
This solution is achieved implementing AbsoluteLayout, CarouselView, IndicatorView and DataTemplateSelector. Xamarin.Forms 4.8 is supposed in what follows. If a lower version is used, please take into account that features like CarouselView or IndicatorView could be in Preview status.
DataTemplateSelector, CarouselView and IndicatorView are used to simulate a TabbedPage, and AbsoluteLayout is used to provide the Overlay.
So, now with the solution:
Create your Views
Here you create a view for each of the pages you want. In this example i want my application to consist of two pages, so i create two views (code behind remains untouched):
View1.xaml
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="overlayTest.View1"
BackgroundColor="Black">
<ContentView.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms 1!"
TextColor="White"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentView.Content>
</ContentView>
View2.xaml
<?xml version="1.0" encoding="UTF-8"?>
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="overlayTest.View2">
<ContentView.Content>
<StackLayout>
<Label Text="Welcome to Xamarin.Forms 2!"
VerticalOptions="CenterAndExpand"
HorizontalOptions="CenterAndExpand" />
</StackLayout>
</ContentView.Content>
</ContentView>
Create a DataTemplateSelector
This will be used by the CarouselView in order to select one view or the other depending on the current Position.
using System;
using Xamarin.Forms;
namespace overlayTest
{
class MyTemplateSelector : DataTemplateSelector
{
readonly DataTemplate view1, view2;
public MyTemplateSelector()
{
view1 = new DataTemplate(typeof(View1));
view2 = new DataTemplate(typeof(View2));
}
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
String s = item.ToString();
if(s == "1")
{
return view1;
}
return view2;
}
}
}
Create your Main Page
Page1.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:t="clr-namespace:overlayTest"
x:Class="overlayTest.Page1">
<ContentPage.Resources>
<ResourceDictionary>
<t:MyTemplateSelector x:Key="templateSelector"/>
</ResourceDictionary>
</ContentPage.Resources>
<ContentPage.Content>
<AbsoluteLayout>
<StackLayout AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
Padding="0"
Spacing="0">
<CarouselView ItemTemplate="{StaticResource templateSelector}"
IndicatorView="indicatorView">
<CarouselView.ItemsSource>
<x:Array Type="{x:Type x:String}">
<x:String>1</x:String>
<x:String>2</x:String>
</x:Array>
</CarouselView.ItemsSource>
</CarouselView>
<IndicatorView x:Name="indicatorView">
<IndicatorView.IndicatorTemplate>
<DataTemplate>
<StackLayout HorizontalOptions="FillAndExpand">
<Frame Margin="10">
<Label/>
</Frame>
</StackLayout>
</DataTemplate>
</IndicatorView.IndicatorTemplate>
</IndicatorView>
</StackLayout>
<ContentView
IsVisible="True" VerticalOptions="Start"
AbsoluteLayout.LayoutBounds="0,0,1,1"
AbsoluteLayout.LayoutFlags="All"
BackgroundColor="Transparent">
<Frame CornerRadius="10"
Margin="20"
VerticalOptions="StartAndExpand"
HorizontalOptions="CenterAndExpand" InputTransparent="False">
<StackLayout Padding="0">
<Label
FontSize="Medium"
TextColor="Black"/>
<StackLayout Orientation="Horizontal"
HorizontalOptions="CenterAndExpand">
<Label Text="I am floating here"/>
<Switch IsToggled="True" />
</StackLayout>
<Button Text="Save"
BackgroundColor="Accent"/>
</StackLayout>
</Frame>
</ContentView>
</AbsoluteLayout>
</ContentPage.Content>
</ContentPage>
And in the code behind we set the name of the tabs. Here please put attention in the fact that i am supposing an element tree of a StackLayout -> Frame -> Label. If you change the IndicatorTemplate, you will have to also modify this part of the code!
Page1.xaml.cs
using System.Linq;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace overlayTest
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class Page1 : ContentPage
{
public Page1()
{
InitializeComponent();
indicatorView.PropertyChanged += (s, a) =>
{
if (a.PropertyName == IndicatorView.HeightProperty.PropertyName)
{
var indicators = indicatorView.IndicatorLayout.Children.ToList();
int counter = 0;
foreach(var indicator in indicators)
{
var indicatorBaseStack = (StackLayout)indicator;
var indicatorFrame = (Frame)indicatorBaseStack.Children[0];
var indicatorFrameLabel = (Label)indicatorFrame.Content;
indicatorFrameLabel.Text = counter == 0 ? "View1" : "View2";
counter++;
}
}
};
}
}
}
Finally set that Page to the MainPage property of App:
public App()
{
InitializeComponent();
MainPage = new Page1();
}
The final result looks like this:
As a workaround, you could set ToolbarItem of each ContentPage (or you can define a base ContentPage).
<ContentPage.ToolbarItems>
<ToolbarItem Text="Example Item"
IconImageSource="xxx.png"
Order="Secondary"
Clicked="{Binding xx}"
Priority="0" />
<ToolbarItem Text="Example Item"
IconImageSource="xxx.png"
Order="Secondary"
Priority="1" />
<ToolbarItem Text="Example Item"
IconImageSource="xxx.png"
Order="Secondary"
Priority="2" />
</ContentPage.ToolbarItems>
I recommend creating a BaseContentPage that includes a static FloatingButton. This allows every page to inherit from BaseContentPage and use the same FloatingButton.
Code
BaseContentPage
abstract class BaseContentPage : ContentPage
{
protected static Button Button { get; } = new Button { Text = $"This button was created at {DateTimeOffset.UtcNow}" }.Invoke(button => button.Clicked += HandleButtonClicked);
static async void HandleButtonClicked(object sender, EventArgs e) =>
await Application.Current.MainPage.DisplayAlert("Button Clicked", "This is the same button on both pages", "OK");
}
Example LabelPage
class LabelPage : BaseButtonPage
{
public LabelPage()
{
Title = "LabelPage";
Content = new StackLayout
{
Children =
{
new Label { Text = "Label Page" }.TextCenter().Center(),
Button
}
}
}
}
Example ButtonPage
class ButtonPage : BaseButtonPage
{
public ButtonPage()
{
Title = "ButtonPage";
Content = Button;
}
}
Example App
public class App : Application
{
public App()
{
Device.SetFlags(new[] { "Markup_Experimental" });
MainPage = new TabbedPage
{
Children =
{
new ButtonPage(),
new LabelPage()
}
};
}
}
Sample App
Here is the sample app used to create the attached GIF:
https://github.com/brminnick/TabbedPageButton/

Update the Counter in Badge, Xamarin Forms app

I'm using this Plugin.Badge to display cart items count on tabbed view in Xamarin Forms app.
here is my tabbed page xaml code MainPage.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"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
xmlns:plugin="clr-namespace:Plugin.Badge.Abstractions;assembly=Plugin.Badge.Abstractions"
xmlns:android="clr-namespace:Xamarin.Forms.PlatformConfiguration.AndroidSpecific;assembly=Xamarin.Forms.Core" android:TabbedPage.ToolbarPlacement="Bottom"
SelectedTabColor="{StaticResource HighlightText}" BarBackgroundColor="{StaticResource HighlightBg}" UnselectedTabColor="Gray"
xmlns:views="clr-namespace:Projectname.Views" x:Class="Projectname.Views.MainPage" >
<TabbedPage.Children>
<NavigationPage Title="Home" IconImageSource="home.png">
<x:Arguments>
<views:HomePage />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="Search" IconImageSource="search.png">
<x:Arguments>
<views:AboutPage />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="Cart" IconImageSource="cart.png"
plugin:TabBadge.BadgeText= "{Binding Counter}"
plugin:TabBadge.BadgeColor="Red"
plugin:TabBadge.BadgeTextColor="White" plugin:TabBadge.BadgePosition="PositionTopRight" >
<x:Arguments>
<views:AboutPage />
</x:Arguments>
</NavigationPage>
<NavigationPage Title="Account" IconImageSource="account.png">
<x:Arguments>
<views:AccountPage />
</x:Arguments>
</NavigationPage>
</TabbedPage.Children>
</TabbedPage>
below is the Code behind in MainPage.xaml.cs
using System;
using System.ComponentModel;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Xamarin.Essentials;
using Plugin.Badge.Abstractions;
using System.Collections.ObjectModel;
//using Xamarin.Forms.PlatformConfiguration.AndroidSpecific;
namespace Projectname.Views
{
[DesignTimeVisible(false)]
public partial class MainPage : TabbedPage
{
int Counter;
public MainPage()
{
InitializeComponent();
Counter = 2;
}
}
}
In one of the tabbedpage children you can see, the badge is set like
plugin:TabBadge.BadgeText= ""{Binding Counter}"
But is not working.
I want to set the value of the badge counter to the value of variable in the code behind page MainPage.xaml.cs
for that what all changes to be done in the code. Please help me on this.
This will not work. You are creating local variable and not even setting binding context.
First of all I recommend to create ViewModel for example:
public class MainPageViewModel : INotifyPropertyChanged
{
private int counter = 0;
public MainPageViewModel()
{
}
public event PropertyChangedEventHandler PropertyChanged;
public int Counter
{
set { counter = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Counter))); }
get { return counter; }
}
}
Then in your MainPage create binding context to viewmodel
public partial class MainPage : TabbedPage
{
private MainPageViewModel viewModel;
public MainPage()
{
InitializeComponent();
viewModel = new MainPageViewModel();
BindingContext = viewModel;
viewModel.Counter = 2;
}
}

Xamarin Forms - binding to a ControlTemplate

I am having trouble getting bindings defined in a ControlTemplate to work against my model.
Notice in the below ControlTemplate, I am using a TemplateBinding to bind to a property called Count (olive label). I am using Parent.Count as prescribed by this article, but neither values of Parent.Count nor Count are working.
The following page uses the ControlTemplate. Just to prove my ViewModel works I have a gray Label bound to the Count property as well.
Notice the resulting screen. The gray label is showing the Count property. The olive label from the ControlTemplate is not showing anything.
How can I make the Label in the ControlTemplate show the Count property from the ViewModel?
VIEW MODEL
namespace SimpleApp
{
public class MainViewModel : INotifyPropertyChanged
{
public MainViewModel()
{
_count = 10;
Uptick = new Command(() => { Count++; });
}
private int _count;
public int Count
{
get { return _count; }
set
{
_count = value;
OnPropertyChanged("Count");
}
}
public ICommand Uptick { get; private set; }
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
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:SimpleApp"
x:Class="SimpleApp.MainPage"
ControlTemplate="{StaticResource ParentPage}">
<StackLayout>
<Button Command="{Binding Uptick}" Text="Increment Count" />
<Label Text="{Binding Count}" BackgroundColor="Gray" />
</StackLayout>
</ContentPage>
CODE BEHIND
Notice the BindingContext is set to MainViewModel here. I need to use my own ViewModel and not the code behind.
namespace SimpleApp
{
public partial class MainPage : ContentPage
{
public MainPage()
{
BindingContext = new MainViewModel();
InitializeComponent();
}
}
}
CONTROL TEMPLATE
<?xml version="1.0" encoding="utf-8" ?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="SimpleApp.App">
<Application.Resources>
<ResourceDictionary>
<ControlTemplate x:Key="ParentPage">
<StackLayout>
<Label Text="{TemplateBinding Parent.Count}" BackgroundColor="Olive" />
<ContentPresenter />
</StackLayout>
</ControlTemplate>
</ResourceDictionary>
</Application.Resources>
</Application>
On your ControlTemplate please use the following code:
<Label Text="{TemplateBinding BindingContext.Count}" BackgroundColor="Olive" />
It seems that BindingContext is not being automatically applied to your ContentPage child, maybe it could be a bug in Xamarin.