0
votes

I have a Xamarin Forms App and I want to put a standard (sub)header on every page. The subheader will contain a label which will change for each page and an optional back button, and will be just below the App Header which contains the menu hamburger and the App Name.

Initially I created a "HeaderPage" which contained the layout for the standard controls, and all my pages inherited from this page. I "hid" the ContentPage.Content so the pages that inherited from HeaderPage could just set Content = to set the HeaderPage Content

    private ContentView _headerPageContent;
    public new View Content
    {
        set { _headerPageContent.Content = value; }
    }

and the child page just had to set the text:

        HeaderLabel = "Contact Us";

This worked great until Forms 2.1 where the ability to mask ContentPage.Content was removed.

At that time the recommendation was to use a ContentPage with a ControlTemplate that has the header. I explored this path, as did one of my co-workers, and we both backed off because of the complexity and duplication of code putting the binding on every page.

I've thought about making the heading a view, or looking into what it would take to make it a control.

For now I took the easy way out and renamed the "Content" variable to "HeaderPageContent" so all the pages that inherit from Header page set HeaderPageContent instead of Content.

Has anyone else done something similar to this? What have you found?

1

1 Answers

0
votes

I've faced same problem on my app and found a solution similar to you.

Create a PageBase class which inherits from Xamarin.Forms.Page

- In that class create a `property` named `PageContent` typeof `View`.(Content will be there)
- (optional)Override the default attribute for class: `[Xamarin.Forms.ContentProperty("PageContent")]` so you will not be have to annotate into xaml each time.
- Override `OnParentSet` method like you want to style the page.

Sample Class & Usage

//PageBase Class

namespace Test.Views.Base
{
    [Xamarin.Forms.ContentProperty("PageContent")]
    public class PageBase: Xamarin.Foorms.Page
    {

        private Grid _mainLayout;
        private Label _headerLabel;
        private Label _footerLabel;

        public View PageContent{get;set;}

        public string HeaderText{get;set;} // you can make this property bindable
        public string FooterText{get;set;} // you can make this property bindable

        public PageBase():base()
        {
            _mainLayout = new Grid();
            _mainLayout.RowDefinitions.Add(new RowDefinition(){Height= new GridLenght(50, GridUnitType.Absolute)}); //Header
            _mainLayout.RowDefinitions.Add(new RowDefinition(){Height= new GridLenght(1, GridUnitType.Star)}); //Content
            _mainLayout.RowDefinitions.Add(new RowDefinition(){Height= new GridLenght(50, GridUnitType.Absolute)}); //Footer

            _headerLabel = new Label();
            _footerLabel = new Label();

            _mainLayout.Children.Add(_headerLabel);
            _mainLayout.Children.Add(_footerLabel);

            Grid.SetRow(_footerLabel,2);
        }

        protected override void OnParentSet()
        {
            base.OnParentSet();

            if(PageContent != null)
            {
                _mainLayout.Children.Add(PageContent);
                Grid.SetRow(PageContent,1);
                this.Content= _mainLayout;
            }

            _headerLabel.Text = HeaderText;
            _footerLabel.Text = FooterText;
        }
    }
}

Here is Xaml

<?xml version="1.0" encoding="utf-8" ?>
<local:PageBase xmlns="http://xamarin.com/schemas/2014/forms"
                xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
                xmlns:local="clr-namespace:Test.Views.Base;assembly=Test"
                xmlns:cell="clr-namespace:Test.Views;assembly=Test"
                x:Class="Test.Views.TestPage"
                HeaderText="Page Header"
                FooterText="Page Footer"
                >

  <local:PageBase.PageContent>
    <!-- Here Goes Page Content -->
  </local:PageBase.PageContent>
</local:PageBase>