3

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.

3 Answers 3

3

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
}
Sign up to request clarification or add additional context in comments.

3 Comments

Im trying to use your library, i find it difficult to follow, there is a no simple example on how to use it, its more on how you made it. Some code snippets are not showing full code and end up not knowing which is which eg i dont know what is details in this github.com/roubachof/Sharpnado.Presentation.Forms/wiki/…
Man, come on, there is a full sample app here: github.com/roubachof/Xamarin-Forms-Practices
Managed to make it work.. playing around it thanks for the this. Want to use it inside shell, whats the best way to do?
1

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.

Comments

-1

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:

  1. 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 }

  2. In your xaml bind your controls to the public bindable properties. For example:

1 Comment

"require you to manually set the binding source for each property" - No, if an element doesn't have its BindingContext set, then it automatically looks at parent (and parent's parent etc) until it finds a BindingContext. That is what gets used.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.