Skyraider
Skyraider

Reputation: 47

What is wrong with this simple data binding (.NET Maui) that I am using?

Okay, I am learning .NET Maui. I've been learning navigation and page layout, and I think I'm getting the hang of that. Then I got to data binding and stalled. From everything I've read, what I have SHOULD work, but it does not.

I have a simple test page with two labels on it. Those two labels are (supposedly) bound to specific properties of a class, and supposedly should show the values in the labels. It does not. In fact, nothing shows, nothing at all.

Okay, I have a test page with the following xaml.

<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="MyNamespace.Pages.TestPage"
             xmlns:toolkit="http://schemas.microsoft.com/dotnet/2022/maui/toolkit" 
             Title="TestPage">

    <Grid Margin="15,15,15,15">
        <Grid.RowDefinitions>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
            <RowDefinition Height="*"></RowDefinition>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        
        <Grid Grid.Row="1" Grid.Column="0" Margin="25,0,25,25" RowSpacing="20" ColumnSpacing="20">
            <Grid.RowDefinitions>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="Auto"></RowDefinition>
                <RowDefinition Height="*"></RowDefinition>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"></ColumnDefinition>
            </Grid.ColumnDefinitions>

            <Label Grid.Row="0" Grid.Column="0" TextColor="White" FontSize="24" FontAttributes="Bold" x:Name="lblOne" BindingContext="{Binding DisplayName, Mode=TwoWay}"></Label>
            <Label Grid.Row="1" Grid.Column="0" TextColor="White" FontSize="24" FontAttributes="Bold" x:Name="lblTwo" BindingContext="{Binding SoundFX, Mode=TwoWay}"></Label>
        </Grid>
    </Grid>
</ContentPage

Please ignore the nested Grids, as the page will eventually hold more. At the moment, all it has is two labels on it, supposedly bound to DisplayName and SoundFX, both string properties of my class. The class holding the values looks like this:

(Note: This has been modified to reflect the answer given by FreakyAli. I installed the Toolkit.mvvm package using nuget, then made the changes he suggested. The labels still did not display.)

public partial class MyItem : ObservableObject
{
    [ObservableProperty]
    private String displayName;

    [ObservableProperty]
    private String soundFX;

    public MyItem(String name, String fxresource)
    {
        DisplayName = name;
        SoundFX = fxresource;
    }
}

And the C# for the TestPage is:

public partial class TestPage : ContentPage
{
    private MyItem _item;

    public TestPage()
    {
    InitializeComponent();
        _item = new MyItem("Name to Display", "SoundFX Value");
        this.BindingContext = _item;
    }
}

Unless I missed something, which is an entirely possible state of affairs as I am learning this on my own, the labels in question should be displaying the appropriate text values, but they actually display nothing. The page is completely blank.

If I change the constructor to eliminate the bindings and simply set the labels.Text, it works fine and the labels display correctly, so I don't think the layout is the problem. It has to be something with the binding.


    public TestPage()
    {
        InitializeComponent();

        //_item = new MyItem("Name to Display", "SoundFX Value");
        //this.BindingContext = _item;

        lblOne.Text = "Name to Display";
        lblTwo.Text = "SoundFX Value";
    }

I am not sure what I am doing wrong with this data binding, and I would appreciate a point in the right direction.

EDIT: Final solution. The problems with my test page were twofold. First, I was not binding to the Text element. Second, I needed to make my class and the individual properties observable by using ObservableObject and ObservableProperty, respectively.

Thanks to FreakyAli for the assist.

Upvotes: 0

Views: 1001

Answers (1)

FreakyAli
FreakyAli

Reputation: 16572

The reason it works in one case and does not in the other has to do with Notifying your property of changes it is an MVVM concept that uses the INotifyPropertyChanged interface to notify the changes that occur to your properties and then display those changes to your View.

Now you can either write the boilerplate yourself

Implementing INotifyPropertyChanged - does a better way exist?

Or you can do what I like to do nowadays using the CommunityToolkit.MVVM's ObserveableProperty Interface

public partial class MyItem : ObserveableObject
{
    [ObservableProperty]
    private String displayName;

    [ObservableProperty]
    private String soundFX;

    public MyItem(String name, String fxresource)
    {
        DisplayName = name;
        SoundFX = fxresource;
    }
}

And now it should work

UPDATE

Your Label is bound to the BindingContext property it should be bound to the Text property

  <Label Grid.Row="0" Grid.Column="0" TextColor="White" FontSize="24" FontAttributes="Bold" x:Name="lblOne" Text="{Binding DisplayName, Mode=TwoWay}"></Label>
  <Label Grid.Row="1" Grid.Column="0" TextColor="White" FontSize="24" FontAttributes="Bold" x:Name="lblTwo" Text="{Binding SoundFX, Mode=TwoWay}"></Label>

I am surprised I did not notice this earlier

Upvotes: 1

Related Questions