Hamburger Menu Xamarin Forms (MasterDetailPage) - xamarin

I'm new enough to use Xamarin, in my Xamarin Forms project I created a Master-Detail Page and in the ListView that represents the menu I wanted to put Title and Icon, for icon images I have to insert each icon in all device projects?
And I also have a small problem, when I click on a menu item and navigate to the selected Detail page, the hamburger menu disappears
MainPageMaster.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"
x:Class="XXX"
Title="Master">
<StackLayout>
<ListView x:Name="MenuItemsListView"
SeparatorVisibility="None"
HasUnevenRows="true"
ItemsSource="{Binding MenuItems}">
<ListView.Header>
<Grid BackgroundColor="#03A9F4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="6"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="6"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="15"/>
<RowDefinition Height="30"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
<Label
Grid.Column="1"
Grid.Row="1"
Text="B1 Term"
HorizontalTextAlignment="Center"
Style="{DynamicResource SubtitleStyle}"/>
</Grid>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout VerticalOptions="FillAndExpand"
Orientation="Horizontal"
Padding="20,10,0,10"
Spacing="20">
<Image Source="{Binding Icon}"
WidthRequest="40"
HeightRequest="40"
VerticalOptions="Center" />
<Label Text="{Binding Title}"
FontSize="Medium"
VerticalOptions="Center"
TextColor="Black"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
File .cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MainPageMaster : ContentPage
{
public ListView ListView;
public MainPageMaster()
{
InitializeComponent();
BindingContext = new MainPageMasterViewModel();
ListView = MenuItemsListView;
}
class MainPageMasterViewModel : INotifyPropertyChanged
{
public ObservableCollection<MainPageMenuItem> MenuItems { get; set; }
public MainPageMasterViewModel()
{
MenuItems = new ObservableCollection<MainPageMenuItem>(new[]
{
new MainPageMenuItem { Id = 0, Icon="ic_menu_home.png",Title = "Home", TargetType = typeof(MainPageDetail) },
new MainPageMenuItem { Id = 1, Title = "Elenco Clienti", TargetType = typeof(ElencoClientiPage) },
new MainPageMenuItem { Id = 2, Title = "Logout", TargetType = typeof(LogOut) }
});
}
#region INotifyPropertyChanged Implementation
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged == null)
return;
PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
}
Screen
In this image, my icon isn't visible but I add an image in Android project

Creating the master-detail page:
Add a content page and change the code as follows :
RootPage.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:local="clr-namespace: your_NameSpace"
x:Class="your_NameSpace.RootPage">
</MasterDetailPage>
RootPage.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class RootPage : MasterDetailPage
{
public RootPage()
{
InitializeComponent();
}
}
Creating its Menu Page:
Add another content page and change the code as follows :
MenuPage.xaml (Design of the actual hamburger menu)
<?xml version="1.0" encoding="UTF-8"?>
<ContentPage BackgroundColor="White"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="your_NameSpace.MenuPage">
<ContentPage.Padding >
<OnPlatform x:TypeArguments="Thickness" iOS=" 0 , 20 , 0 , 0" />
</ContentPage.Padding>
<ContentPage.Content>
<StackLayout BackgroundColor="White" Padding ="10 , 30 , 10, 10">
<Button Text="Login" BackgroundColor="White" TextColor="DarkGray" HorizontalOptions="StartAndExpand" Command="{Binding GoHomeCommand}" />
<BoxView HeightRequest="0.5" HorizontalOptions="FillAndExpand" BackgroundColor="Gray"/>
<Button Text="Search" BackgroundColor="White" TextColor="DarkGray" HorizontalOptions="StartAndExpand" Command="{Binding GoSecondCommand}" />
<BoxView HeightRequest="0.5" HorizontalOptions="FillAndExpand" BackgroundColor="Gray"/>
<Button Text="Browse" TextColor="DarkGray" BackgroundColor="White" HorizontalOptions="StartAndExpand" Command="{Binding GoThirdCommand}"/>
<BoxView HeightRequest="0.5" HorizontalOptions="FillAndExpand" BackgroundColor="Gray"/>
</StackLayout>
</ContentPage.Content>
MenuPage.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MenuPage : ContentPage
{
public MenuPage()
{
BindingContext = new MenuPageViewModel();
this.Icon = "yourHamburgerIcon.png"; //only neeeded for ios
InitializeComponent();
}
}
Its model class :
This is where the button click commands of the menu page are bound in
MenuPageViewModel.cs
public class MenuPageViewModel
{
public ICommand GoHomeCommand { get; set; }
public ICommand GoSecondCommand { get; set; }
public ICommand GoThirdCommand { get; set; }
public MenuPageViewModel()
{
GoHomeCommand = new Command(GoHome);
GoSecondCommand = new Command(GoSecond);
GoThirdCommand = new Command(GoThird);
}
void GoHome(object obj)
{
App.NavigationPage.Navigation.PopToRootAsync();
App.MenuIsPresented = false;
}
void GoSecond(object obj)
{
App.NavigationPage.Navigation.PushAsync(new Home()); //the content page you wanna load on this click event
App.MenuIsPresented = false;
}
void GoThird(object obj)
{
App.NavigationPage.Navigation.PushAsync(new ClinicInformation());
App.MenuIsPresented = false;
}
}
Add the following properties in your application class usually, the name for your application class is App.xaml and App.xaml.cs
Add the following to your App.xaml.cs:
public static NavigationPage NavigationPage { get; private set; }
public static RootPage RootPage;
public static bool MenuIsPresented
{
get
{
return RootPage.IsPresented;
}
set
{
RootPage.IsPresented = value;
}
}
Here RootPage is a static instance of your master-detail page,
NavigationPage is your detail page that you change to change your detail page,
IsMenuPresentend is the bool than when true keeps the MenuPage open and when false closes the same.
After doing all this add this function in your application class and call it in its constructor of your App.Xaml.cs
private void CallMain()
{
var menuPage = new MenuPage();
NavigationPage = new NavigationPage(new Home());
RootPage = new RootPage();
RootPage.Master = menuPage;
RootPage.Detail = NavigationPage;
MainPage = RootPage;
}
In your Android project add the following theme:
values/styles.xml
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MyTheme" parent="MyTheme.Base">
</style>
<style name="DrawerArrowStyle"
parent="#style/Widget.AppCompat.DrawerArrowToggle">
<item name="spinBars">true</item>
<item name="color">#FFFFFF</item>
</style>
<style name="MyTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="windowNoTitle">true</item>
<item name="windowActionBar">false</item>
<item name="colorPrimary">#003399</item>
<item name="colorPrimaryDark">#003399</item>
<item name="colorControlHighlight">#003399</item>
<item name="colorAccent">#012348</item>
<item name="drawerArrowStyle">#style/DrawerArrowStyle</item>
</style>
</resources>
Create a folder named values-v21 and add an XML named styles.xml and add the following code to it :
<?xml version="1.0" encoding="utf-8" ?>
<resources>
<style name="MyTheme" parent="MyTheme.Base">
<item name="android:windowContentTransitions">true</item>
<item name="android:windowAllowEnterTransitionOverlap">true</item>
<item name="android:textAllCaps">false</item>
<item name="android:windowAllowReturnTransitionOverlap">true</item>
<item name="android:windowSharedElementEnterTransition">#android:transition/move</item>
<item name="android:windowSharedElementExitTransition">#android:transition/move</item>
</style>
</resources>
And use the name myTheme as the app theme in all your Android activities.
There you go your hamburger menu is complete in case you have any queries feel free to comment.
Good luck!
Happy Coding.

You can try this as well for detailed information
Hamburger Menu tutorial

To show Humberger menu icon in Android and iOS application you can use Title = "☰" a special character. This going to show menu icon properly.
<MasterDetailPage.Master>
<ContentPage Title = "☰" BackgroundColor="Red">
<StackLayout BackgroundColor = "#B2EC5D" >
< ListView x:Name="navigationDrawerList">
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>

Related

ZXing QRCode Scanner Xamarin

I tried to implement the package ZXing.Net.Mobile.Forms
this is my xaml:
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:zxing="clr-namespace:ZXing.Net.Mobile.Forms;assembly=ZXing.Net.Mobile.Forms"
Title="{Binding Title}">
<ContentPage.Content>
<StackLayout>
<Label x:Name="scanResultText" />
<zxing:ZXingScannerView
OnScanResult="ScanViewOnScanResult"/>
</StackLayout>
</ContentPage.Content>
and this my xaml.cs :
public partial class QRCodePage : ContentPage
{
public QRCodePage()
{
InitializeComponent();
BindingContext = new QRCodeViewModel();
}
public void ScanViewOnScanResult(Result result)
{
Device.BeginInvokeOnMainThread(async () =>
{
scanResultText.Text = result.Text;
});
}
}
On my device i visualize the fragment but it seems not scanning
Try adding the following code (IsScanning="True") to your xaml:
<StackLayout>
<Label x:Name="scanResultText" />
<zxing:ZXingScannerView IsScanning="True"
OnScanResult="ScanViewOnScanResult"/>
</StackLayout>

Xamarin reuse viewmodel on user control

In my MainPage.xaml, which is a ContentPage, I have two user controls.
Both of which are ContentView and are loaded like this:
<local:MyView2 HorizontalOptions="Start"
VerticalOptions="Fill">
<local:MyView2.BindingContext>
<viewmodels:NavbarViewModel />
</local:MyView2.BindingContext>
<local:MyView2.Triggers>
<DataTrigger TargetType="{x:Type local:MyView2}" Binding="{Binding IsPresented}" Value="True">
<DataTrigger.EnterActions>
<local:MenuTrigger IsPresented="True"/>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<local:MenuTrigger IsPresented="False" />
</DataTrigger.ExitActions>
</DataTrigger>
</local:MyView2.Triggers>
</local:MyView2>
// omitted myview1, they are basically the same
My MainPage has a different viewmodel than MyView1 and 2 which are the contentviews.
But the bindingcontext I have said is not accessible from inside the contentview:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Universal_ONE.MyView1"
x:Name="MyView1Name">
<Frame BackgroundColor="#385C6C"
Padding="0,0,0,0">
<ImageButton Source="outline_menu_white_24.png"
Command="{Binding Source={x:Reference MyView1Name}, Path=PresentMenu}}"
WidthRequest="24"
HeightRequest="24"
Margin="15,0,0,0"
BackgroundColor="Transparent"
HorizontalOptions="StartAndExpand" />
</Frame>
</ContentView>
I also tried it like this:
<ContentView xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Universal_ONE.MyView1">
<Frame BackgroundColor="#385C6C"
Padding="0,0,0,0">
<ImageButton Source="outline_menu_white_24.png"
Command="{Binding PresentMenu}"
WidthRequest="24"
HeightRequest="24"
Margin="15,0,0,0"
BackgroundColor="Transparent"
HorizontalOptions="StartAndExpand" />
</Frame>
</ContentView>
The error I get on the PresentMenu: No DataContext found for binding PresentMenu
How do I access the bindingcontext inside my contentview?
If it was not clear already, the contentviews are in a seperate file.
EDIT:
NavbarViewModel:
public class NavbarViewModel : INotifyPropertyChanged
{
public NavbarViewModel()
{
isPresented = false;
PresentMenu = new Command(() => IsPresented = !IsPresented);
}
bool isPresented;
public bool IsPresented
{
get => isPresented;
set
{
isPresented = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsPresented)));
}
}
public event PropertyChangedEventHandler PropertyChanged;
public ICommand PresentMenu { private set; get; }
}
EDIT 2:
I have added:
x:DataType="viewmodels:NavbarViewModel
To both contentviews, this removes the error that it has no DataContext. However, the binding still does not work.
Working solution:
I have now added the viewmodel as a staticresource in app.xaml and just reuse that everywhere including in the user controls. I hope to look at this again at some point in the future.

Override Content on ContentView

I am trying to do something i thought would be simple but i havent been able to find the solution yet.
I have a pretty basic custom element for adding a thick border within a frame.
XAML
<?xml version="1.0" encoding="UTF-8" ?>
<Frame
x:Class="ResumeApp.CustomElements.BetterFrame"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Name="OuterFrame"
HorizontalOptions="FillAndExpand"
OutlineColor="Black">
<Frame
x:Name="InnerFrame"
HorizontalOptions="FillAndExpand"
OutlineColor="Black" />
</Frame>
CodeBehind
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ResumeApp.CustomElements
{
[XamlCompilation(XamlCompilationOptions.Compile)]
[ContentProperty(nameof(Content))]
public partial class BetterFrame : Frame
{
private int _Thickness = 0;
public int Thickness
{
get { return _Thickness; }
set
{
Padding = new Thickness(value); _Thickness = value;
}
}
public float Corner
{
get { return InnerFrame.CornerRadius; }
set
{
InnerFrame.CornerRadius = value; OuterFrame.CornerRadius = value;
}
}
public new View Content
{
get
{
//Breakpoint not hit here
return (View)GetValue(ContentProperty);
}
set
{
//breakpoint not hit here
SetValue(ContentProperty, value);
}
}
public Color InnerColor { get { return InnerFrame.BackgroundColor; } set { InnerFrame.BackgroundColor = value; } }
public Color OuterColor { get { return OuterFrame.BackgroundColor; } set { OuterFrame.BackgroundColor = value; } }
public new Color BorderColor { get { return InnerFrame.BorderColor; } set { InnerFrame.BorderColor = value; OuterFrame.BorderColor = value; } }
public BetterFrame()
{
InitializeComponent();
}
protected override void OnParentSet()
{
base.OnParentSet();
for (Element Parent = this.Parent; Parent != null; Parent = Parent.Parent)
{
try
{
Color background = Parent.GetPropertyIfSet<Color>(BackgroundColorProperty, Color.Transparent);
if (background != Color.Transparent && InnerFrame.BackgroundColor != Color.Transparent)
{
InnerFrame.BackgroundColor = background;
break;
}
}
catch
{
}
}
}
}
}
So using the code above when there is no content inside the frame everything looks as expected but once i add content it overwrites the InnerFrame . is there any way of making it so that when i add Content i add it to the InnerFrame instead of the Outter Frame. I added the Content Property to try and catch it being set but i never hit breakpoints set on it so i dont think it is being used.
If adding conetent in another Xaml , it will override the inner Frame . Becasue added content is a child view for outer Frame , and Fram only can own one child view . So the inner Frame will be override .
<local:BetterFrame>
<StackLayout BackgroundColor="AliceBlue">
<Entry x:Name="myentry2"
Text="Second Entry" />
</StackLayout>
</local:BetterFrame>
Here will not show the inner Frame :
Therefore , if adding Content in BetterFrame directly , it will show .
<?xml version="1.0" encoding="utf-8" ?>
<Frame 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:Name="OuterFrame"
x:Class="AppEntryTest.BetterFrame"
HorizontalOptions="FillAndExpand"
OutlineColor="Black">
<Frame x:Name="InnerFrame"
HorizontalOptions="FillAndExpand"
OutlineColor="Black">
<StackLayout BackgroundColor="AliceBlue">
<Entry x:Name="myentry2"
Text="Second Entry" />
</StackLayout>
</Frame>
</Frame>
The effect :
=============================Update================================
Create a custom ContentView and contain Outer Frame and Ineer Frame :
<?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:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="AppEntryTest.Controls.CustomFrameView">
<ContentView.ControlTemplate>
<ControlTemplate >
<Frame x:Name="FrameExtContainer"
Padding="5"
HasShadow="False"
HorizontalOptions="FillAndExpand"
CornerRadius="5"
OutlineColor="Black"
BorderColor="Black">
<Frame x:Name="FrameIntContainer"
Padding="15"
Margin="12"
HasShadow="False"
HorizontalOptions="FillAndExpand"
CornerRadius="5"
OutlineColor="Black"
BorderColor="Black">
<ContentPresenter />
</Frame>
</Frame>
</ControlTemplate>
</ContentView.ControlTemplate>
</ContentView>
Now used in another Xaml can work:
<local:CustomFrameView>
<StackLayout BackgroundColor="AliceBlue">
<Entry x:Name="myentry3"
Text="Third Entry" />
</StackLayout>
</local:CustomFrameView>
The effect :

How to make a local ContentView bind a Label text

I made a ContentView with an Expander. I want to duplicate this Xaml code multiple times in an other Xaml file. But I want for each Expander a different Binding.
I linked this code (ContentView code):
<?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:expandable="clr-namespace:Expandable;assembly=ExpandableView"
x:Class="Hello.ExpandableView">
<ContentView.Content>
<expandable:ExpandableView Padding="5">
<expandable:ExpandableView.PrimaryView>
<Frame BackgroundColor="White" Padding="5" CornerRadius="10">
<StackLayout Orientation="Horizontal">
<Label x:Name="label" FontSize="16" TextColor="Black" FontAttributes="Bold" Padding="5" HorizontalTextAlignment="Start" HorizontalOptions="StartAndExpand"/>
<Image Source="arrow.png" WidthRequest="25" HeightRequest="25" Margin="5"/>
</StackLayout>
</Frame>
</expandable:ExpandableView.PrimaryView>
<expandable:ExpandableView.SecondaryViewTemplate>
<DataTemplate>
<Frame BackgroundColor="White" Padding="5" CornerRadius="10">
<Label Text="{Binding Tip1Uitleg}" FontSize="15" TextColor="Black" Padding="5"/>
</Frame>
</DataTemplate>
</expandable:ExpandableView.SecondaryViewTemplate>
</expandable:ExpandableView>
</ContentView.Content>
</ContentView>
namespace Hello
{
public partial class ExpandableView : ContentView
{
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged: (b, o, n) => (b as ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
}
}
To this code:
This works:
<local:ExpandableView Label="Hello"/>
But I want this. This does not work:
<?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:expandable="clr-namespace:Expandable;assembly=ExpandableView"
xmlns:local="clr-namespace:Hello"
x:Class="Hello.Health.HealthDetail"
Title="{Binding Name}">
<ContentPage.Content>
<ScrollView>
<StackLayout>
<Image Source="{Binding Image}"/>
<Label Text="{Binding Tip1Uitleg}" FontSize="15" TextColor="Black" Padding="10, 5, 10, 5"/>
<local:ExpandableView Label="{Binding Tip1}"/> //This is what it is all about
</StackLayout>
</ScrollView>
</ContentPage.Content>
</ContentPage>
CodeBehind:
namespace Hello.Health
{
public partial class HealthDetail : ContentPage
{
public HealthDetail(HealthStrings healthStrings)
{
if (healthStrings == null)
throw new ArgumentNullException();
BindingContext = healthStrings;
InitializeComponent();
}
}
}
How do I make this work? I have to make this above more dynamic, but I do not know how.
BTW This also works:
<Label Text="{Binding Tip1}" />
I am sorry for the unclear explanation, I hope someone can help me.
Thank you for your time :)
You should not bind to 'this' since you are using a BindableProperty. Instead you should update the Label.Text property when the value of the BindableProperty changes.
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged:(b, o, n) => (b as ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
<?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="YourProject.ExpandableView">
<Grid>
<Label x:Name="label"/>
</Grid>
</ContentView>
Normally, when you want to binding a value for binableproperty, you could try the code below:
ExpandableView: I make a simple contentview with the same binableproperty for you reference.
<?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="XamarinDemo.Pages.ExpandableView">
<ContentView.Content>
<StackLayout>
<Label Text="Hello"></Label>
<Label x:Name="label"></Label>
</StackLayout>
</ContentView.Content>
</ContentView>
Code behind:
public partial class ExpandableView : ContentView
{
public static BindableProperty LabelProperty =
BindableProperty.Create(nameof(Label),
typeof(string),
typeof(ExpandableView),
propertyChanged: (b, o, n) => (b as
ExpandableView).OnLabelChanged());
private void OnLabelChanged()
{
label.Text = Label; //label is the x:Name of your Label control in ExpandableView.xaml
}
public string Label
{
get => (string)GetValue(LabelProperty);
set => SetValue(LabelProperty, value);
}
public ExpandableView()
{
InitializeComponent();
}
}
Usage:
<ContentPage.Content>
<local:ExpandableView Label="{Binding str}"></local:ExpandableView>
</ContentPage.Content>
Code Behind:
public partial class Page1 : ContentPage
{
public string str { get; set; }
public Page1()
{
InitializeComponent();
str = "okay";
this.BindingContext = this;
}
}

How to Create a UserControl using MVVM in Xamarin.Forms

I have tried to develop a usercontrol in Xamarin.Forms but I am not able to bind the controls of that Usercontrol using ViewModel.
My CustomeEntryUserControl is look like
<?xml version="1.0" encoding="UTF-8"?>
<Grid xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="LearningApp.UserControls.CustomeEntry"
xmlns:local="clr-namespace:LearningApp.Extension">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="20" />
</Grid.ColumnDefinitions>
<Entry Grid.Column="0" x:Name="entry" />
<local:RoundedButton Grid.Column="1" Text="X" BackgroundColor="Gray" TextColor="White" HeightRequest="20" WidthRequest="10" VerticalOptions="Center" Margin="-30,0,30,0" x:Name="cancelbtn" />
</Grid>
Code behind of this usercontrol is look like
public partial class CustomeEntry : Grid
{
public CustomeEntry()
{
InitializeComponent();
}
public static readonly BindableProperty TextProperty = BindableProperty.Create(nameof(Text), typeof(string), typeof(CustomeEntry), default(string));
public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(CustomeEntry), typeof(ICommand), default(ICommand));
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public string Text
{
get { return (string)GetValue(TextProperty); }
set { SetValue(TextProperty, value); }
}
public string PlaceHolder
{
get { return entry.Placeholder; }
set { entry.Placeholder = value; }
}
}
I have tried to use this control in one of my content page is like
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="LearningApp.Views.TriggersDemo.DataTriggers"
xmlns:local="clr-namespace:LearningApp.UserControls">
<StackLayout Orientation="Vertical">
<Label FontSize="Large" FontAttributes="Bold" Text="{Binding lblText}"></Label>
<local:CustomeEntry Text="{Binding Name}" Command="{Binding CancelCommand}" PlaceHolder="Enter Name"/>
<Button Command="{Binding CheckCommand}" Text="Check" />
</StackLayout>
</ContentPage>
code behind of above mentioned content page is
namespace LearningApp.Views.TriggersDemo
{
public partial class DataTriggers : ContentPage
{
public DataTriggers()
{
InitializeComponent();
this.BindingContext = new TriggersViewModel();
}
}
}
and My ViewModel contain the one Property like
private string _Name;
public string Name
{
get { return _Name; }
set { _Name = value; RaisePropertyChanged(); }
}
Can anyone please guide how I can bind the Entry Text of UserControl to my ViewModel property Name direct?
In you CustomerEntry there is no control that displays the Text you're binding to.
You have to set up all the bindings in your custom control too.
You can also pass a handler to the TextProperty's `propertyChanged' parameter, and set other view's properties on behalf.
Remove the properties from the custom control and bind directly to the BindingContext which will be passed along (containing you viewmodel).
Then set Text="{Binding Text=.}" in your custom control's entry (same with Button's Command) to have it bind to the text from the BindingContext, in fact you can remove all your properties from the custom control, and bind directly to the ViewModel.

Resources