I want to create a very basic custom control that will update its label if the label changes in the containing view model
My setup is like this:
public partial class BindTest : ContentView
{
public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(BindTest), string.Empty, propertyChanged: TitleChanged);
static void TitleChanged(BindableObject bindable, object oldValue, object newValue)
{
var control = (BindTest)bindable;
control.Title = newValue as string;
}
public string Title
{
get => (string)GetValue(BindTest.TitleProperty);
set => SetValue(BindTest.TitleProperty, value);
}
public BindTest()
{
InitializeComponent();
}
}
<?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="MauiDemo.BindTest" x:Name="this">
<StackLayout BindingContext="{x:Reference this}">
<Label TextColor="White" Text="{Binding Title}" />
</StackLayout>
</ContentView>
And i consume my custom control like this and bind my property from my VM (annotated as ObservableProperty)
<controls:BindTest Title="{Binding TestString}"/>
<Label Text="{Binding TestString}"/>
If i press a Button that executes a command my TestString will be overriden and updated correctly. the separate label beneath my custom controls displays the changing value correctly.
did i misinterpret the use case of custom controls or is something wrong the way i setup things?
CodePudding user response:
This is not the correct way to create custom controls because this way you will always run into BindingContext related issues as soon as your control becomes a part of another view and the BindingContext gets shared to the branches of that View.
So your code should look like below:
<?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="MauiDemo.BindTest" x:Name="this">
<StackLayout>
<Label TextColor="White" Text="{Binding Title, Source={x:Reference this}}" />
</StackLayout>
</ContentView>
You can check my MAUI library that handles different kinds of custom controls https://github.com/FreakyAli/Maui.FreakyControls.
Hope it helps :)
CodePudding user response:
Ok, so i found out, that i indeed messed up my setup for creating a custom control.
As i already stated, the problem was that the custom control wouldn't get updated even if the BindableProperty would update.
The BindableProperty would always properly update but the propertyChanged callback would never be called again after the initial value override.
So now i was wondering, why would the propertyChanged callback only be called once?
The root of my problem was the line control.Title = value as string;
Removing just this one line and leaving the rest of the setup as-is resulted in the custom control correctly updating if the BindableProperty was updated.
Which means, that by calling the setter of the property used by the custom control somehow interrupts the way maui connects the bindings for the properties.
Therefore i missinterpreted the use of the propertyChanged callback, due to the influence on random samples out there in the web.
I will leave the working class and uses down below so u can just test/try out and see how bindings work in custom controls if anybody happens to stumble across the same or similar problems.
BindTest.xaml.cs
public partial class BindTest : ContentView
{
public static readonly BindableProperty TitleProperty = BindableProperty.Create(nameof(Title), typeof(string), typeof(BindTest), string.Empty);
public string Title
{
get => (string)GetValue(BindTest.TitleProperty);
set => SetValue(BindTest.TitleProperty, value);
}
public BindTest()
{
InitializeComponent();
}
}
BindTest.xaml
<?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="MauiDemo.Controls.BindTest" x:Name="this">
<StackLayout BindingContext="{x:Reference this}">
<Label TextColor="White" Text="{Binding Title}" />
</StackLayout>
</ContentView>
usage in different view
<?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:controls="clr-namespace:MauiDemo.Controls"
x:Class="MauiDemo.Test">
<StackLayout>
<controls:BindTest Title="{Binding TestString}"/>
</StackLayout>
</ContentView>