Search code examples
c#xamlxamarinxamarin.forms

Value not binding in XAML Page in Xamarin.Forms


I have a text that is changing dynamically and needs to be updated in user interface, but it is not binding.

Here is the view model:

internal class PowerViewModel : INotifyPropertyChanged
{
    public string Power { get; set; }
    
    public PowerViewModel()
    {  
        MessagingCenter.Instance.Subscribe<App, string>(this, "power_topic", OnPowerChanged);
    }
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    private void OnPowerChanged(App app, string power)
    {
        Power = power;
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(Power)));
    }
}

the method OnPowerChanged() is being triggered and Power is taking a value.

The view code and binding is this:

namespace IotApp.Views
{
    public partial class ItemDetailPage : ContentPage
    {
        public ItemDetailPage()
        {
            InitializeComponent();
            BindingContext = new PowerViewModel();
            BindingContext = new ItemDetailViewModel();
        }
    }
}

And here is the xaml code:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:viewmodels="clr-namespace:IotApp.ViewModels" x:DataType="viewmodels:PowerViewModel"
             x:Class="IotApp.Views.ItemDetailPage">
    <ContentPage.BindingContext>
        <viewmodels:PowerViewModel />
    </ContentPage.BindingContext>
    
    <ContentPage.Background>
        <LinearGradientBrush StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="#faeee2" Offset="0.1"/>
            <GradientStop Color="#a0bec6" Offset="0.5"/>
        </LinearGradientBrush>
    </ContentPage.Background>
        
    <Shell.TitleView>
        <StackLayout Orientation="Horizontal">
            <Label Text="Home" FontSize="16"/>
            <Image Source="logo_white" VerticalOptions="EndAndExpand" HorizontalOptions="EndAndExpand"/>
        </StackLayout>
    </Shell.TitleView>
    
    <StackLayout Spacing="20" Padding="15" VerticalOptions="Start">
    
        <Label Text="{Binding Power}"  FontSize="18" TextColor="#1c2d57" />
    
    </StackLayout>
    
</ContentPage>

It should show the value of Power, but is empty all the time, I just can't figure out why. Please, help.

Thank you very much.


Solution

  • Problem

    The problem is that you're setting the BindingContext multiple times.

    You set it twice here:

    namespace IotApp.Views
    {
        public partial class ItemDetailPage : ContentPage
        {
            public ItemDetailPage()
            {
                InitializeComponent();
                BindingContext = new PowerViewModel();
                BindingContext = new ItemDetailViewModel();
            }
        }
    }
    

    And a third time here:

    <ContentPage.BindingContext>
        <viewmodels:PowerViewModel />
    </ContentPage.BindingContext>
    

    The second assignment in the code-behind takes precedence, so you're effectively trying to bind to the wrong ViewModel.

    Solution

    Remove the assignment of the BindingContext in the XAML and also remove the second assignment in the code behind, so that the code looks like this:

    namespace IotApp.Views
    {
        public partial class ItemDetailPage : ContentPage
        {
            public ItemDetailPage()
            {
                InitializeComponent();
                BindingContext = new PowerViewModel();
            }
        }
    }