Xamarin.Forms: bind to a code behind property in XAML - c#

In Xamarin.Forms I would like to bind a code behind property to a label in XAML.
I found many answers and web pages about this topic, but they all cover more complex scenarios.
This is my XAML 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:local="clr-namespace:TrackValigie"
x:Class="TrackValigie.SelViaggioPage">
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding ?????????}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
And this is code behind:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SelViaggioPage : ContentPage
{
private string _lblText;
public string LblText
{
get
{
return _lblText;
}
set
{
_lblText = value;
OnPropertyChanged();
}
}
public SelViaggioPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
this.LblText = "Ciao!!";
base.OnAppearing();
}
}
I would like to bind the "LblText" property to the label, using XAML only, that means without setting binding or binding context in code behind.
Is this possible?

your page will need to implement INotifyPropertyChanged, but the binding syntax should just be
<ContentPage x:Name="MyPage" ... />
...
<Label BindingContext="{x:Reference Name=MyPage}" Text="{Binding LblText}" />

Or if you don't want to swap the binding context for the entire control then use the following:
<?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:Name="this"
x:Class="SomePage">
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding SomeProp, Source={x:Reference this}}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>

Just add BindingContext = this; in code behind file.
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:TrackValigie"
x:Class="TrackValigie.SelViaggioPage">
<ContentPage.Content>
<StackLayout>
<Label Text="{Binding LblText}" />
</StackLayout>
</ContentPage.Content>
</ContentPage>
Code Behind
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class SelViaggioPage : ContentPage
{
private string _lblText;
public string LblText
{
get
{
return _lblText;
}
set
{
_lblText = value;
OnPropertyChanged();
}
}
public SelViaggioPage()
{
InitializeComponent();
BindingContext = this;
}
protected override void OnAppearing()
{
base.OnAppearing();
this.LblText = "Ciao!!";
}
}

You need to set the x:Name for ContentPage as mentioned by Jason's Answer .
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:TrackValigie"
x:Class="TrackValigie.SelViaggioPage"
x:Name = "MyControl"/>
Instead of using BindingContext, you can use ElementName
<TextBlock Text="{Binding ElementName=TestControl,Path=StudentName}"/>

Related

.net Maui binding values multiple levels deep

How can I Pass a Binding from a Page to a View?
I have this Page(Xaml)
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:DataBindingTests.Views"
xmlns:model="clr-namespace:DataBindingTests.ViewModels"
x:Class="DataBindingTests.Pages.CoolePage"
Title="CoolePage"
x:DataType="model:CoolesModel">
<VerticalStackLayout>
<Label Text="{Binding YourName}"></Label>
<views:MainView YourName="{Binding YourName}"></views:MainView>
<Button Command="{Binding ChangeNameCommand}"></Button>
</VerticalStackLayout>
</ContentPage>
And its CodeBehind:
using DataBindingTests.ViewModels;
namespace DataBindingTests.Pages;
public partial class CoolePage : ContentPage
{
public CoolePage()
{
this.BindingContext = new CoolesModel();
InitializeComponent();
}
}
If I pass a String into my MainView it works and all events are fired. When I use the binding it doesn't. In this simple test, the app should display two times the same name, but only the Label of the ContentPage has the YourName property printed
<views:MainView YourName="Lars"></views:MainView> <-- Works
<views:MainView YourName="{Binding YourName}"></views:MainView> <-- doesn't work
This is the Xaml of the MainView
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:views="clr-namespace:DataBindingTests.Views"
x:Class="DataBindingTests.Views.MainView">
<VerticalStackLayout>
<Label Text="{Binding YourName}"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentView>
This is the CodeBehind of the MainView
namespace DataBindingTests.Views;
public partial class MainView : ContentView
{
public String YourName
{
get
{
String value = (String)GetValue(MainView.YourNameProperty);
return value;
}
set
{
SetValue(MainView.YourNameProperty, value);
}
}
public static readonly BindableProperty YourNameProperty = BindableProperty.Create(nameof(YourName)
, typeof(String)
, typeof(MainView), defaultBindingMode:BindingMode.TwoWay, propertyChanged: OnYourNameChanged);
static void OnYourNameChanged(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine(newValue);
}
public MainView()
{
this.BindingContext = this; // Ignore ParentContext
InitializeComponent();
}
}
You can just remove code this.BindingContext = this; from the constructor of MainView.xaml.cs:
public MainView()
{
//this.BindingContext = this;
InitializeComponent();
}
Update:
the above code would only work because the Property in the View and
the Page have the same name.
In this condition, you can modify the code of MainView.xaml as follows:
<?xml version="1.0" encoding="utf-8" ?>
<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp929.MainView"
x:Name="TestControlView"
>
<VerticalStackLayout>
<Label Text="{Binding Source={x:Reference TestControlView}, Path=YourName}"
VerticalOptions="Center"
HorizontalOptions="Center" />
</VerticalStackLayout>
</ContentView>
MainView.xaml.cs
public partial class MainView : ContentView
{
public String YourName
{
get
{
String value = (String)GetValue(YourNameProperty);
return value;
}
set
{
SetValue(YourNameProperty, value);
}
}
public static readonly BindableProperty YourNameProperty = BindableProperty.Create(nameof(YourName)
, typeof(String)
, typeof(MainView), defaultBindingMode: BindingMode.TwoWay, propertyChanged: OnYourNameChanged);
static void OnYourNameChanged(BindableObject bindable, object oldValue, object newValue)
{
Console.WriteLine("-----------------> "+newValue);
}
public MainView()
      {
            InitializeComponent();
// this.BindingContext = this;
}
}
CoolesModel.cs
public class CoolesModel
{
// public string YourName { get; set; }
public string Name { get; set; }
public string TestName { get; set; }
public ICommand ChangeNameCommand => new Command(changeMethod);
private void changeMethod()
{
}
public CoolesModel() {
//YourName = "abc";
Name = "abc";
TestName = "test123...";
}
}
MainPage.xaml.cs
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:mauiapp929="clr-namespace:MauiApp929"
x:Class="MauiApp929.MainPage">
<ScrollView>
<VerticalStackLayout>
<Label Text="{Binding Name}"></Label>
<mauiapp929:MainView YourName="{Binding TestName}"></mauiapp929:MainView>
<Button Command="{Binding ChangeNameCommand}"></Button>
</VerticalStackLayout>
</ScrollView>
</ContentPage>
In this simple test, the app should display two times the same name, but only the Label of the ContentPage has the YourName property printed
You're overwriting your binding context half way through for some reason, and the context your page binding resolves (the normal way of using it, the parent context) is different than what you actually see on the screen (which is your this.BindingContext = this). And you never set your second context's property.

Binding on Property not working in Xamarin

I am trying to create a custom ContentView that can be used throughout my Xamarin.Froms application in de xaml views. The binding on IconColor is not working. I followed the documentation ContentView but it does not seem to work. The Color of the FontImageSource is never set. What am I missing here?
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
x:Class="Peripass.Mobile.Framework.UIControls.PeripassIcon"
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">
<ContentView.Resources>
</ContentView.Resources>
<ContentView.Content>
<StackLayout HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image>
<Image.Source>
<FontImageSource x:Name="_icon" Glyph="" Color="{Binding IconColor}" Size="20" FontFamily="{OnPlatform Android=PeripassIcon.ttf#}" />
</Image.Source>
</Image>
</StackLayout>
</ContentView.Content>
</ContentView>
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Peripass.Mobile.Framework.UIControls {
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class PeripassIcon : ContentView {
public static readonly BindableProperty IconSizeProperty = BindableProperty.Create(nameof(IconSize), typeof(double), typeof(PeripassIcon), 26.0);
public static readonly BindableProperty IconColorProperty = BindableProperty.Create(nameof(IconColor), typeof(Color), typeof(PeripassIcon), Color.White);
public static readonly BindableProperty IconNameProperty = BindableProperty.Create(nameof(IconName), typeof(IconType?), typeof(PeripassIcon));
public PeripassIcon() {
InitializeComponent();
}
public IconType IconName {
get => (IconType)GetValue(IconNameProperty);
set => SetValue(IconNameProperty, value);
}
public double IconSize {
get => (double)GetValue(IconSizeProperty);
set => SetValue(IconSizeProperty, value);
}
public Color IconColor {
get => (Color)GetValue(IconColorProperty);
set => SetValue(IconColorProperty, value);
}
protected override void OnPropertyChanged(string propertyName = null) {
base.OnPropertyChanged(propertyName);
if (propertyName == IconNameProperty.PropertyName) {
_icon.Glyph = $"&#x{(int)IconName:X4};";
}
}
}
}
<StackLayout Grid.Row="1" Grid.Column="0">
<uiControls:PeripassIcon IconName="{Binding Model.Icon}" IconColor="#EE4022" IconSize="85.5"/>
</StackLayout>
I needed to set the BindingContext like this:
<?xml version="1.0" encoding="UTF-8" ?>
<ContentView
x:Class="Peripass.Mobile.Framework.UIControls.PeripassIcon"
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="this">
<ContentView.Resources>
</ContentView.Resources>
<ContentView.Content>
<StackLayout BindingContext="{x:Reference this}" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand">
<Image>
<Image.Source>
<FontImageSource x:Name="_icon" Glyph="" Color="{Binding IconColor}" Size="{Binding IconSize}" FontFamily="{OnPlatform Android=PeripassIcon.ttf#}" />
</Image.Source>
</Image>
</StackLayout>
</ContentView.Content>
</ContentView>
A best practice in MVVM is to keep Views separate from ViewModels, so the best approach is to set BindingContext to the ViewModel (not View via {x:Reference this}).
Make sure that either in Code behind or in Xaml the page binding context is set to your ViewModel, the rest is defined correctly.

Xamarin.Forms Binding to Custom Control Not Working When Binding Is Set In Parent

I'm trying to create a simple Xamarin.Forms custom control and I've encountered on a problem with binding.
This was my initial custom control:
<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="CubisMobile.Controls.TestControl"
x:Name="TestControlView">
<Label Text="{Binding TestText}" />
public partial class TestControl : ContentView
{
public static readonly BindableProperty TestTextProperty = BindableProperty.Create(nameof(TestText), typeof(string), typeof(TestControl));
public string TestText
{
get { return (string)GetValue(TestTextProperty); }
set { SetValue(TestTextProperty, value); }
}
public TestControl()
{
InitializeComponent();
BindingContext = this;
}
}
And I was trying to use it this way:
...
<StackLayout>
<controls:TestControl TestText="{Binding Title}" />
<Label Text="{Binding Title}" />
</StackLayout>
...
I added the second label to test if the Title property works fine, and it does.
But text does not show up on the custom control. When I set a constant value like TestText="Testing" it works as it should. I found this answer on StackOverflow, tried the following, but it also didn't work (custom control XAML):
<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="CubisMobile.Controls.TestControl"
x:Name="TestControlView">
<Label Text="{Binding Source={x:Reference TestControlView}, Path=TestText}" />
I really don't understand why this binding doesn't work.
The answer you found is the good one, I did the same in my library:
<tabs:TabItem x:Class="Sharpnado.Presentation.Forms.CustomViews.Tabs.UnderlinedTabItem"
xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:tabs="clr-namespace:Sharpnado.Presentation.Forms.CustomViews.Tabs;assembly=Sharpnado.Presentation.Forms"
x:Name="RootLayout">
<ContentView.Content>
<Grid BackgroundColor="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Style="{StaticResource TabTextHeader}"
FontFamily="{Binding Source={x:Reference RootLayout}, Path=FontFamily}"
FontSize="{Binding Source={x:Reference RootLayout}, Path=LabelSize}"
Text="{Binding Source={x:Reference RootLayout}, Path=Label}"
TextColor="{Binding Source={x:Reference RootLayout}, Path=UnselectedLabelColor}">
And the code behind:
public static readonly BindableProperty FontFamilyProperty = BindableProperty.Create(
nameof(FontFamily),
typeof(string),
typeof(TabItem),
null,
BindingMode.OneWay);
public string FontFamily
{
get => (string)GetValue(FontFamilyProperty);
set => SetValue(FontFamilyProperty, value);
}
The only issue I see in the code you shown is the setting of the BindingContext:
public TestControl()
{
InitializeComponent();
BindingContext = this; // Remove this line
}
I have test your code , we need to pay attention to several places:
1. Suppose the class name of ContentView is TestControl, you can try to the following code as you mentioned:
<?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="CustomeViewApp1.controls.TestControl"
x:Name="TestControlView"
>
<ContentView.Content>
<Label Text="{Binding Source={x:Reference TestControlView}, Path=TestText}" />
</ContentView.Content>
2. remove code BindingContext = this; in TestControl.xaml.cs
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class TestControl : ContentView
{
public static readonly BindableProperty TestTextProperty = BindableProperty.Create(nameof(TestText), typeof(string), typeof(TestControl));
public string TestText
{
get { return (string)GetValue(TestTextProperty); }
set { SetValue(TestTextProperty, value); }
}
public TestControl()
{
InitializeComponent();
//BindingContext = this;
}
}
The test xaml I used is as follows:
<StackLayout Orientation="Horizontal" HorizontalOptions="Center">
<controls:TestControl TestText="{Binding Title}" VerticalOptions="Center"/>
<Label Text="{Binding Type}" FontSize="Medium" TextColor="#F0BB7F"
FontAttributes="Bold" VerticalOptions="Center"/>
</StackLayout>
And you can check the full demo I test here.
The provided answers work fine. However, these require you to manually set the binding source for each property. This can become tedious if a lot of properties need binding.
A simpler approach will be to override the OnChildAdded event exposed by the framework and set the binding context there. This will automatically set the binding context for any child added.
To do this follow these steps:
In the code-behind file add the following method:
protected override void OnChildAdded(Xamarin.Forms.Element child)
{
base.OnChildAdded(child); //must be called for base implementations to be applied
child.BindingContext = this; //this sets the binding context for added children
}
In your xaml bind your controls to the public bindable properties. For example:

CarouselView.Content is empty

I try study is new componet CarouselView and с# in total.
But I have problem.
This code display is empty content in CarouselView. Why?
I send is fill code my colutions.
<?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:carousel="clr-namespace:CarouselView.FormsPlugin.Abstractions;assembly=CarouselView.FormsPlugin.Abstractions"
xmlns:local="clr-namespace:App6"
x:Class="App6.MainPage">
<StackLayout>
<Image Source="home.png"/>
<carousel:CarouselViewControl x:Name="MyCV" BackgroundColor="Black">
<carousel:CarouselViewControl.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="{Binding TestLine}"></Label>
</StackLayout>
</DataTemplate>
</carousel:CarouselViewControl.ItemTemplate>
</carousel:CarouselViewControl>
</StackLayout>
</ContentPage>
namespace App6
{
public partial class MainPage : ContentPage
{
class CustomCell
{
public string TestLine { get; set; }
}
public MainPage()
{
InitializeComponent();
List<CustomCell> myCarousel = new List<CustomCell>();
myCarousel.Add(new CustomCell { TestLine = "Line 1" });
myCarousel.Add(new CustomCell { TestLine = "Line 2" });
MyCV.ItemsSource = myCarousel;
}
}
}
Your code is correct, so your problem is in the visual layer. Try to define the height and width wherever possible and it should resolve the problem. CarouselView isn't the official control and isn't up to standards of Xamarin's built-in controls so it has some somewhat unexpected behaviors like this.

Xamarin ToolbarItem Icon not showing in Android

I have a problem when trying to load the Icon of a ToolbarItem in Xamarin: It doesn't show up. The toolbar certainly exists. I have handled the Click method and it works, but the Icon is not visible. the ".ico" file exists in all the "drawable" folders in the Android project. It's the same .ico file I use in another solution and there it works just fine as the icon of a ToolbarItem, but here it doesn't work. I have tried to load an embedded image, but it doesn't work either. If I set its Text property, it is shown properly. I have a HomePage which is a MasterDetailPage, and the detail of this page is RootPage. On RootPage I have the ToolbarItem. Here are my xaml codes and the code behind:
HomePage:
<?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:ITEC.Views;assembly=ITEC"
x:Class="ITEC.Views.HomePage"
IsPresented="True">
<MasterDetailPage.Master>
<ContentPage Title="Home" Padding="0,20,0,0">
<StackLayout>
<ListView x:Name="listView">
<ListView.ItemTemplate>
<DataTemplate>
<TextCell Text="{Binding Title}"/>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackLayout>
</ContentPage>
</MasterDetailPage.Master>
<MasterDetailPage.Detail>
<views:RootPage/>
</MasterDetailPage.Detail>
</MasterDetailPage>
Code behind:
using ITEC.Services;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ITEC.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class HomePage : MasterDetailPage
{
private OptionService _optionService;
public HomePage()
{
InitializeComponent();
Detail=new NavigationPage(new RootPage());
_optionService = new OptionService();
listView.ItemsSource = _optionService.GetOptions();
}
}
}
RootPage:
<?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:embedded="clr-namespace:ITEC.MarkupExtensions"
x:Class="ITEC.Views.RootPage">
<ContentPage.ToolbarItems>
<ToolbarItem Icon="settings.ico" Clicked="MenuItem_OnClicked"></ToolbarItem>
</ContentPage.ToolbarItems>
<StackLayout>
<Label>Hello world</Label>
</StackLayout>
</ContentPage>
Code behind:
using System;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace ITEC.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class RootPage : ContentPage
{
public RootPage()
{
InitializeComponent();
}
private void MenuItem_OnClicked(object sender, EventArgs e)
{
DisplayAlert("Hello", "OK", "No");
}
}
}
Try png file for your icon. i think it might be work.

Categories