2
votes

I am implementing a Xamarin app with FreshMVVM framework and I want to use a BasePage to share some code among Pages. The problem is that when I need to bind some Properties in the MainPage.xaml I have to specify the Source in this way to make it working: Text="{Binding Title, Source={x:Reference mainPage}}". Otherwise without Source Binding doesn't work. Ok, I get it but is this the right way? Is there another way to achieve the same result? What about when I have plenty of bindings in a page? For instance, is it possible "setting" the Source at un upper level, because in my opinion setting the same Source for each Binding is very annoying.

BasePage.xaml

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestXamarin.BasePage"
             x:Name="basePage">
    <ContentView>
        <StackLayout Orientation="Vertical">
            <Label Text="HEADER" FontSize="Large"/>
            <Label Text="{Binding Text, Source={x:Reference basePage}}" FontSize="Large"/>
            <ContentPresenter BindingContext="{Binding Parent.BindingContext}" 
                              Content="{Binding PageContent, Source={x:Reference basePage}}" />
        </StackLayout>
    </ContentView>
</ContentPage>

BasePage.xaml.cs

using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace TestXamarin
{
	[XamlCompilation(XamlCompilationOptions.Compile)]
	public partial class BasePage : ContentPage
	{
		public static readonly BindableProperty TextProperty = BindableProperty.Create(
			   nameof(Text),
			   typeof(string),
			   typeof(BasePage));

		public string Text
		{
			get { return (string)GetValue(TextProperty); }
			set { SetValue(TextProperty, value); }
		}

		public static readonly BindableProperty PageContentProperty = BindableProperty.Create(
			   nameof(PageContent),
			   typeof(object),
			   typeof(BasePage));

		public object PageContent
		{
				get { return GetValue(PageContentProperty); }
				set { SetValue(PageContentProperty, value); }
		}

		public BasePage()
		{
			InitializeComponent();
		}
	}
}

MainPage.xaml

<local:BasePage xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:local="clr-namespace:TestXamarin"
                x:Class="TestXamarin.MainPage"
                Text="FROM MAIN PAGE"
                x:Name="mainPage">
    <local:BasePage.PageContent>
        <StackLayout>
            <Label Text="Body" FontSize="Large"/>
            <Label Text="{Binding Title, Source={x:Reference mainPage}}" FontSize="Large"/>
        </StackLayout>
    </local:BasePage.PageContent>
</local:BasePage>

MainPage.xaml.cs

public partial class MainPage : BasePage
	{
		public MainPage()
		{
			Title = "MAIN PAGE";

			InitializeComponent();
		}
	}
1
Are you using an MVVM framework? If not I would advise you to look into it because it can greatly simplify your binding experience. - Steven Thewissen
Only BindingContext supports property value inheritance, not Source - Sharada Gururaj
@StevenThewissen Actually I am using FreshMVVM, but it seems to have same problem. - user2297037

1 Answers

4
votes

Another way to achieve what you are trying to do would be with control templates.

Here I have defined a template in App.xaml

<ControlTemplate x:Key="ActivityIndicatorTemplate">
    <Grid>
        <ContentPresenter />
        <StackLayout Style="{StaticResource BlockingPanel}"
                     IsVisible="{TemplateBinding BindingContext.IsBusy}">
            <ActivityIndicator Style="{StaticResource ActivityIndicatorStyle}"
                               IsVisible="{TemplateBinding BindingContext.IsBusy}"
                               IsRunning="{TemplateBinding BindingContext.IsBusy}" />
        </StackLayout>
    </Grid>
</ControlTemplate>

Note the content presenter and the TemplateBinding.

I use it on a page like this.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Test.MyTestPage"
             ControlTemplate="{StaticResource ActivityIndicatorTemplate}"
             Title="{Binding Title}">

    <Grid>
    ...
    </Grid>
</ContentPage>

The page content replaces the content presenter in the template. Looks simpler than a base page.